API de InferNode
Ruta base: https://api.<tu-dominio>/infernode/v1. Autenticación con Authorization: Bearer sk-saptiva-.... Compatible con el SDK de OpenAI (ver Usar la API desde código).
Inferencia
| Método y ruta | Descripción |
|---|---|
POST /v1/chat/completions | Chat. Campos: model, messages, stream, temperature, top_p, max_tokens, n, stop, presence_penalty, frequency_penalty, seed, tools, tool_choice, response_format, logprobs, top_logprobs. Los parámetros de razonamiento thinking_token_budget, chat_template_kwargs (enable_thinking, reasoning_budget) y reasoning (effort) se reenvían al modelo sin interpretarlos (cabecera X-Saptiva-Passthrough). Con stream: true responde por SSE con el formato de chunks de OpenAI. |
POST /v1/embeddings | Vectores. model, input (string o lista), dimensions (hasta el máximo del modelo, 4096 en el de la plataforma), encoding_format (float o base64). |
POST /v1/images/generations | Genera imágenes. Cuerpo: preset (nombre del modelo de imagen del Catálogo), prompt (hasta 4096 caracteres), n (1 a 4), size (por defecto 1024x1024). Devuelve el resultado o un trabajo con job_id si la generación es asíncrona. Cuenta contra el límite de imágenes por minuto. |
GET /v1/images/generations/{job_id} | Estado y resultado del trabajo. |
POST /v1/guard | Evalúa un texto contra las categorías de riesgo. |
GET /v1/guard/events | Evaluaciones registradas de tu Cliente. |
Ejemplo de petición y respuesta
Los ejemplos llaman por alias, que es lo recomendado: el nombre exacto del Catálogo también se acepta, pero cambia cuando se actualiza el modelo. La respuesta devuelve en model el modelo que contestó, no el alias con el que llamaste.
curl https://api.<tu-dominio>/infernode/v1/chat/completions -i \
-H "Authorization: Bearer sk-saptiva-..." -H "Content-Type: application/json" \
-d '{"model": "Saptiva Turbo", "messages": [{"role": "user", "content": "Hola"}], "max_tokens": 64}'
HTTP/1.1 200 OK
X-Request-Id: req_01J9X4M2K7
X-RateLimit-Remaining-Requests: 58
X-RateLimit-Remaining-Tokens: 199872
X-Request-Cost: 0.0004
X-Credits-Remaining: 1249.31
{
"id": "chatcmpl-...",
"object": "chat.completion",
"model": "Qwen3.6 35B A3B (FP8)",
"choices": [{ "index": 0, "message": { "role": "assistant", "content": "Hola, ¿en qué puedo ayudarte?" }, "finish_reason": "stop" }],
"usage": { "prompt_tokens": 9, "completion_tokens": 11, "total_tokens": 20 }
}
Un error usa la envoltura de OpenAI con request_id:
{ "error": { "type": "rate_limit_error", "code": "rate_limit_exceeded", "message": "Token limit exceeded, resets in 42s", "request_id": "req_01J9X4M2K7" } }
Lotes
Peticiones asíncronas en un archivo, compatibles con la API Batch de OpenAI. Guía en Procesar peticiones en lote. Si la instalación no los tiene habilitados, estas rutas responden 404.
| Método y ruta | Descripción |
|---|---|
POST /v1/files | Sube el archivo de entrada. Multipart con purpose=batch (único valor aceptado) y file. Devuelve un objeto con id, bytes, filename, purpose, status y created_at. El mismo contenido subido dos veces devuelve el archivo existente, con la cabecera X-Saptiva-Deduplicated-From |
GET /v1/files | Archivos de la organización |
GET /v1/files/{file_id} | Metadatos de un archivo |
GET /v1/files/{file_id}/content | Descarga los bytes. Responde con X-Saptiva-Content-SHA256. Es la única forma de descargar: no hay enlaces temporales |
DELETE /v1/files/{file_id} | Borra un archivo. Un archivo de entrada usado por un lote vivo responde 400 file_in_use |
POST /v1/batches | Crea el lote. Cuerpo: input_file_id, endpoint (/v1/chat/completions o /v1/embeddings), completion_window (solo "24h", sin promesa de entrega) y metadata opcional |
GET /v1/batches | Lotes de la organización. limit de 1 a 100 (20 por defecto) y after con un id de lote como cursor |
GET /v1/batches/{batch_id} | Estado y resultado del lote |
POST /v1/batches/{batch_id}/cancel | Cancela. Desde finalizing o un estado terminal responde 400 batch_not_cancellable |
El objeto del lote trae status, input_file_id, output_file_id, error_file_id, endpoint, model, completion_window, metadata, request_counts (total, completed, y failed, que suma las líneas fallidas, canceladas y expiradas), errors.data, usage al terminar, y las marcas de tiempo de cada transición (created_at, in_progress_at, expires_at, finalizing_at, completed_at, failed_at, expired_at, cancelling_at, cancelled_at).
errors.data lleva las causas cuando falla el archivo entero y, cuando el lote lo canceló alguien que no es su dueño, una entrada cancelled_by_org_admin o cancelled_by_platform_admin.
Estados: validating, in_progress, finalizing, cancelling, y los terminales completed, failed, cancelled y expired.
El archivo de salida trae solo las líneas que terminaron bien; el resto va al de errores. Los archivos de entrada y de salida caducan a los 30 días por defecto, con la fecha en expires_at.
Cada línea se cobra como la llamada equivalente, sin descuento. El movimiento lleva el endpoint marcado, visible en last_event.endpoint de GET /v1/billing/balance (/v1/chat/completions:batch). Las líneas no consumen los límites por minuto; las llamadas de esta sección sí.
Modelos
| Método y ruta | Descripción |
|---|---|
GET /v1/models | Modelos disponibles para la llave. |
GET /v1/models/{name} | Detalle: type, provider, capabilities, context_window, max_output_tokens, pricing (input, output, unit, currency) y deprecation (deprecated_at, retires_at). Con un alias, cabecera X-Alias-Of. |
GET /v1/models/aliases | Alias públicos y el modelo al que apuntan. |
Cuenta y llaves
| Método y ruta | Descripción |
|---|---|
GET /v1/me | org, user, membership, plan (con is_billing_exempt y has_rate_limits) y api_key con la que llamaste. |
GET /v1/me/orgs | Organizaciones a las que perteneces. |
GET /v1/me/api-keys | Llaves del usuario (sin el secreto). |
POST /v1/me/api-keys | Crear una llave. El secreto se muestra una sola vez. |
POST /v1/me/api-keys/{id}/rotate | Rotar: nueva llave, la anterior deja de valer. |
DELETE /v1/me/api-keys/{id} | Revocar. |
Consumo
| Método y ruta | Descripción |
|---|---|
GET /v1/billing/balance | credits_remaining, initial_credits, spending_caps, usage_this_month, last_event; is_billing_exempt indica si el plan descuenta créditos. |
GET /v1/billing/usage?period=AAAA-MM | total_requests, total_tokens_in, total_tokens_out, total_cost, by_model, by_api_key, daily_breakdown (y by_user para administradores). |
GET /v1/billing/transactions | Movimientos de créditos. |
Cabeceras de respuesta
X-Request-Id, X-RateLimit-Limit-Requests, X-RateLimit-Remaining-Requests, X-RateLimit-Reset-Requests, X-RateLimit-Limit-Tokens, X-RateLimit-Remaining-Tokens, X-RateLimit-Reset-Tokens, X-Request-Cost, X-Credits-Remaining, X-Credits-Warning, X-Model-Deprecated, X-Model-Retires-At, X-Alias-Of, X-Saptiva-Passthrough, X-Saptiva-Model-Defaults; en un 429, además Retry-After. En respuestas en streaming las cabeceras de tokens no se envían (el conteo ocurre después de emitir la cabecera). Significado en InferNode.
Errores
Envoltura OpenAI ampliada: {"error": {"type", "code", "message", "param", "request_id", "details"}}. code lleva el módulo como prefijo cuando aplica (identity.invalid_token, identity.org_suspended) o es plano (model_not_found, rate_limit_exceeded, insufficient_credits, parameter_not_supported). Tipos: invalid_request_error, authentication_error, permission_error, not_found_error, billing_error, rate_limit_error, provider_error, maintenance_error, internal_error. Un 429 trae details.dimension (rpm, rpd, tpm, tpd, ipm). Detalle en Códigos de error.
Las operaciones de administración de la plataforma (alta de modelos, límites por Cliente, créditos, auditoría) están bajo /v1/admin/* y /v1/billing/admin/*, reservadas al operador.