Respuesta corta: conciliar una factura de API de LLM requiere tres capas de datos que usted mismo pueda recalcular, no la promesa de un proveedor de «facturación transparente». La primera capa es la tarea individual: en HopBase, cuando termina una tarea de video o de imagen asíncrona, la respuesta de su consulta incluye usage.cost_usd, el importe realmente descontado de su saldo por esa tarea (las respuestas síncronas no streaming incluyen el mismo campo); un fallo no cobrado informa 0, y basta un comando curl para comprobarlo. La segunda capa es el registro detallado: la página Usage de la consola exporta un CSV filtrado por fecha, clave, miembro, departamento o creador de la clave, y cada fila incluye el costo oficial, el descuento, el tipo de cambio y el importe cobrado para verificar línea por línea que costo oficial × descuento ÷ tipo de cambio = importe cobrado. La tercera capa es la asignación: cada clave muestra su creador, existen gráficas de gasto por clave, los responsables de departamento ven y gestionan las claves y el uso de su propio departamento, y se pueden fijar cuotas por clave, miembro y departamento. Con las tres capas implantadas, el cargo interno a un departamento se reduce a un filtro y una exportación.
Por qué las facturas de LLM son difíciles de conciliar
Una empresa que usa a la vez modelos de chat, imagen y video maneja al menos cuatro unidades de facturación: tokens para el chat, imágenes para la mayoría de los modelos de imagen, segundos o tokens de video para el video, y tarifas fijas por llamada para algunos otros. Si a eso se suman unos cuantos problemas prácticos, las cifras dejan de cuadrar:
- Las tareas asíncronas se tarifican al terminar. Un envío de video solo lleva una estimación; el cargo real se conoce cuando la tarea finaliza, y los proveedores difieren en si una tarea fallida cuesta algo y cuánto.
- Solicitudes fallidas. Una solicitud fallida normalmente es gratuita, pero cuando el cliente se desconecta después de que ya se generó salida, la parte generada suele facturarse. Si la factura no lo indica, surge la clásica disputa de «dio error y aun así me cobraron».
- Monedas. Los precios oficiales de lista están mayoritariamente en dólares estadounidenses, mientras que el saldo de la cuenta puede llevarse en otra moneda. Sin el tipo de cambio intermedio, nadie puede recalcular el cargo.
- Claves compartidas. Cuando varios proyectos comparten una clave, nadie puede saber después quién gastó qué.
Así que el objetivo es concreto: cada cargo debe poder rastrearse hasta una tarea o solicitud, una clave, la persona que creó esa clave y un departamento, y el importe debe poder recalcularse a partir de los precios de lista publicados.
Capa 1: el cargo real, directamente desde la consulta de la tarea
Cuando una tarea asíncrona (video, imagen asíncrona, etc.) se completa, falla o se cancela, la respuesta de la consulta de tarea individual incorpora un objeto usage de nivel superior:
usage.cost_usdes el importe realmente descontado de su saldo en USD por esa tarea, la misma cifra que figura en el registro de uso;usage.costes el mismo cargo expresado en CNY, yusage.currencyindica la moneda decost(siempreCNY); concilie concost_usd;- una tarea fallida que no se cobró informa
0; en el caso poco frecuente de que una tarea de imagen falle después de liquidarse su cargo (por ejemplo, si el modelo no devolvió ninguna imagen utilizable), informa el cargo real; - el campo no aparece mientras la tarea está en ejecución, y solo la clave que creó la tarea lo ve.
Se aplica a GET /v1/video/tasks/{task_id} (Seedance, Grok Imagine, Kling, MiniMax, Midjourney), GET /api/v1/tasks/{task_id} (Wan, HappyHorse) y GET /v1/images/tasks?task_id=... (tareas asíncronas de imagen de GPT Image y Gemini). Comprobarlo requiere un solo comando:
# Query with the key that submitted the task; jq keeps only status and cost
curl -s https://api.hop-base.com/v1/video/tasks/$TASK_ID \
-H "Authorization: Bearer $HOPBASE_API_KEY" \
| jq '{status: (.task.status // .status), usage}'
# Once the task has finished you get something like (amount illustrative):
# { "status": "completed", "usage": { "cost": 2.4, "cost_usd": 0.352941, "currency": "CNY" } }
En una respuesta de Seedance, task.usage es el número de tokens facturables y el usage.cost_usd de nivel superior es el dinero: no los confunda. En MiniMax y Wan, que ya devuelven un usage de nivel superior, cost_usd, cost y currency se fusionan en él. La ventaja práctica: su propio sistema puede escribir el cargo real en su registro de pedido o de trabajo en el momento en que termina la tarea, en lugar de consultar la consola o contabilizar la estimación del envío como costo.
Capa 2: registros detallados que pueden recalcularse fila por fila
Las solicitudes síncronas no crean ninguna tarea. Una respuesta JSON no streaming incluye los mismos campos usage.cost_usd / usage.cost (además de las cabeceras de respuesta X-HopBase-Cost-USD); las respuestas en streaming no pueden incluirlos, así que para ellas el importe está en los registros de uso. El botón de exportación de la página Usage de la consola descarga un CSV que respeta los filtros de la página (rango de fechas, clave, miembro, departamento, creador de la clave), con hasta 50,000 filas y 400 días por archivo. Cada fila tiene trece columnas:
- Hora, Modelo, Uso (tokens totales, incluidas las lecturas y escrituras de caché);
- Moneda del precio oficial de lista, Costo oficial (en la moneda de lista);
- Descuento, Tipo de cambio, Cobrado (USD);
- Nota;
- API Key, Estado de la clave, Usuario, Departamento.
Leídas de izquierda a derecha, cuatro de esas columnas son la propia fórmula de verificación: costo oficial × descuento ÷ tipo de cambio = importe cobrado. Cuando la moneda del precio de lista y la del saldo coinciden, la celda del tipo de cambio queda vacía y la fórmula pasa a ser costo oficial × descuento = importe cobrado. Usted puede calcular el costo oficial con la propia página de precios del proveedor, y el descuento es el de su grupo del plan, así que cada fila puede comprobarse de forma independiente sin fiarse de los totales de nadie. Las filas que no pueden cumplir la fórmula (registros antiguos sin instantánea del precio de lista, o llamadas tarificadas con una tarifa fija por imagen o por llamada) dejan esas cuatro columnas vacías en lugar de mostrar un cero engañoso.
Las solicitudes fallidas se anotan como «Solicitud fallida, no cobrada»; una solicitud interrumpida después de generarse salida se anota como «Solicitud interrumpida, cobrada por el uso ya generado», y al final del archivo se cuentan ambas. Esas son precisamente las filas que provocan disputas, así que dejar la regla escrita en el registro es mejor que explicarla después. Para automatizar, GET /v1/usage con una API key devuelve el saldo y el uso de la cuota de esa clave.
Capa 3: asignación por clave y por departamento
La asignación empieza con una clave por centro de costo. Las cuentas empresariales de HopBase tienen miembros y departamentos, y unos pocos hechos determinan si la asignación funciona de verdad:
- Cada clave muestra su creador. Las claves que creó un miembro y las que el propietario o un responsable de departamento creó y asignó a un miembro siguen siendo distinguibles, y las exportaciones pueden filtrarse por creador.
- Gráficas de gasto por clave. La consola muestra la tendencia de gasto, el número de solicitudes y la combinación de modelos por clave, de modo que un gasto inusual apunta directamente a una clave.
- Alcance del responsable de departamento. Un responsable de departamento ve y gestiona las claves y el uso de los miembros de su propio departamento, puede crear claves para esos miembros y no puede ver otros departamentos. El propietario ve toda la empresa. Cuando un miembro cambia de departamento, el alcance lo acompaña.
- Cuotas por capas. Se pueden fijar cuotas por clave, por miembro y por departamento, y alcanzar cualquiera de ellas bloquea la solicitud con un 402 cuyo mensaje indica si se agotó la cuota de la clave, del miembro o del departamento, no un vago «saldo insuficiente».
El cargo interno mensual a un departamento consiste entonces en elegir el departamento y el mes en la página Usage y exportar. Cada departamento obtiene su propio archivo detallado y puede recalcularlo con la fórmula anterior.
Una lista de verificación de conciliación aplicable a cualquier proveedor
- Cuando termina una tarea asíncrona, ¿puede obtener su cargo real desde la API, y no una estimación o un costo base?
- ¿Puede exportar registros detallados con costo oficial, descuento y tipo de cambio, y recalcular cada fila?
- ¿Se etiquetan por separado las solicitudes fallidas y las «interrumpidas después de generarse salida»?
- ¿Cada importe indica su moneda, y el tipo de cambio es visible cuando la moneda del precio de lista y la del saldo difieren?
- ¿Puede filtrar las exportaciones por clave, miembro y departamento, y cada clave registra su creador?
- ¿Las cuotas pueden organizarse por capas, y un error de cuota le indica qué capa se agotó?
- ¿Está recibiendo realmente el modelo por el que paga? Compruébelo usted mismo con nuestro método de verificación de fidelidad del modelo.
Cada punto puede comprobarse con curl o con un archivo exportado, lo que hace que la lista sirva frente a cualquier proveedor, incluidos nosotros.
Preguntas frecuentes
¿El usage.cost_usd de la consulta de la tarea es lo mismo que el importe cobrado en la consola?
Sí. usage.cost_usd es el importe cobrado que figura en el registro de uso de esa tarea, es decir, lo que realmente bajó su saldo, así que puede cotejarlo uno a uno con los registros exportados.
¿Por qué no hay usage.cost_usd mientras la tarea sigue en ejecución?
El cargo final de una tarea asíncrona solo se conoce cuando termina; cualquier cifra devuelta antes solo podría ser una estimación. Por eso el campo aparece cuando la tarea se completa, falla o se cancela. Mientras se ejecuta, siga consultando como de costumbre.
¿Se cobran las tareas fallidas?
Las tareas de video fallidas nunca se cobran, y la consulta informa usage.cost_usd como 0. En casos poco frecuentes, una tarea de imagen falla después de liquidarse su cargo; la consulta informa entonces el cargo real, y el mismo importe aparece en sus registros de uso. Las solicitudes síncronas fallidas son gratuitas; una solicitud interrumpida después de generarse salida se cobra por lo generado y se etiqueta como tal en la exportación.
¿Por qué otra clave no ve el costo de mi tarea?
El costo solo se devuelve a la clave que creó la tarea. Así se mantiene intacto el límite de «una clave por centro de costo» y se impide que otras claves de la misma cuenta vean un gasto que no les corresponde.
¿Las solicitudes de chat también tienen un importe por solicitud?
Sí, en las solicitudes no streaming: el cuerpo de la respuesta incluye usage.cost_usd y las cabeceras incluyen X-HopBase-Cost-USD. Las respuestas en streaming no, porque el cargo solo se conoce cuando termina el stream; use los registros de uso de la consola, donde la exportación CSV permite recalcular cada fila, y el filtrado junto con la exportación le da los totales por clave o por departamento.