Casi todo lo que haces dentro de StockAI también se puede hacer por API: subir ventas, entrenar, leer el semáforo, registrar órdenes, administrar proveedores y bodegas. Así puedes conectarlo a tu ERP, tu POS o cualquier sistema propio.
Cada llamada lleva una API key en la cabecera Authorization. Las claves se crean en la app, en Automatización → API Keys, y se muestran una sola vez: StockAI guarda solo un hash.
Una clave actúa como sí misma, no como la persona que la creó: sigue funcionando si esa persona deja la empresa.
Claves de lectura y de escritura
Al crear una clave eliges qué puede hacer. Cada endpoint de la referencia dice qué tipo de clave necesita.
Lectura
Lee todo lo que un usuario visor ve: semáforo, pronósticos, proveedores, órdenes, reportes.
Lectura y escritura
Además crea y modifica, como un analista: sube archivos, entrena, registra órdenes, edita inventario y proveedores.
Una clave de lectura que intenta escribir recibe 403 con error_code api_key_scope_insufficient, y no cambia nada.
Lo que una clave nunca puede hacer
Algunas acciones son de personas, no de sistemas. Con una API key responden 403 api_key_route_not_exposed:
Iniciar sesión, refrescar tokens o recuperar contraseñas.
Crear, invitar o modificar usuarios y sus permisos.
Crear, listar o revocar API keys: una clave no puede crear otra.
Configurar la instalación o los canales de la cuenta.
Exportar o borrar la cuenta.
Lo que es de una persona: su bandeja de mensajes, sus conversaciones con el asistente, sus preferencias.
Lo que solo un administrador puede hacer (por ejemplo, cambiar la moneda o el período activo).
Enviar una orden o una alerta por correo o WhatsApp con una clave de escritura exige que la cuenta tenga al menos un administrador con el correo verificado (si no: 403 api_key_tenant_unverified).
Límites
Autenticación
/ min
120 llamadas por minuto por clave, en los planes que incluyen la API.
API
Plan gratis y cuentas de prueba: la API no está incluida; empieza en el plan completo.
/ 24 h
Plan completo: 2000 llamadas por día por clave (ventana de 24 horas).
/ 24 h
Plan corporativo: sin tope diario.
Al pasarte recibes 429 con la cabecera Retry-After (segundos). El mismo 429 sirve para el límite por minuto y para el tope diario, y su cuerpo no trae error_code.
No hay cabeceras X-RateLimit-*: la única señal es el 429 con Retry-After. Cuenta tus llamadas o espera el 429.
Medición y precio
La API viene desde el plan completo, con un tope diario de llamadas por clave; el volumen mayor se acuerda con nosotros. Contamos cada llamada con una API key que llegó a un endpoint, por día (UTC) y por clave; las rechazadas (clave inválida, sin permiso o por encima del límite) no cuentan. Un administrador ve el consumo del mes en la app, en la pantalla API.
Casi todo error trae un error_code estable y, si aplica, error_params con los valores: ramifica por el código, no por el texto de detail, que es una ayuda en inglés y puede cambiar. Las respuestas del propio framework (cabecera ausente, ruta inexistente, método incorrecto) y el 429 solo traen detail.
api_key_invalid
401 la clave no existe, fue revocada o venció.
api_key_route_not_exposed
403 ese endpoint no se puede usar con una API key.
api_key_scope_insufficient
403 la clave es de lectura y el endpoint escribe.
api_key_tenant_unverified
403 enviar algo fuera de StockAI exige un administrador verificado.
validation_error
422 el cuerpo o los parámetros no son válidos; detail es una lista con un objeto por campo.
PLAN_LIMIT_REACHED
403 llegaste a un tope del plan; detail es un objeto y error_params dice cuál.
server_busy
503 el servidor está saturado; reintenta según Retry-After.
(sin error_code)
401 falta la cabecera Authorization o no es “Bearer sk_live_…”: detail es “Not authenticated”.
(sin error_code)
429 límite por minuto o tope diario: espera Retry-After segundos.
(sin error_code)
404 / 405 ruta inexistente o método no permitido.
La forma de detail
texto
La mayoría de los errores: una frase en inglés.
lista
422 validation_error: [{ type, loc, msg, input }], uno por campo inválido; loc dice dónde (por ejemplo ["body", "name"]).
objeto
PLAN_LIMIT_REACHED: { code, limit, current, max, tier }, el mismo contenido que error_params.
403 Ejemplo: clave de lectura que escribe
{"detail":"This endpoint writes and the API key is read-only. Use a write key.","error_code":"api_key_scope_insufficient","error_params":{"required_scope":"write","key_scope":"read"}}
El formato de respuesta
Toda respuesta JSON viene envuelta: { "success": true, "data": …, "meta": { "timestamp": … } }. Lo tuyo está en data, que según el endpoint es un objeto o una lista; los listados paginados traen la lista en data.items.
Los endpoints que devuelven un archivo (Excel, PDF, CSV) responden el archivo directamente, sin envoltorio.
El endpoint MCP (POST /mcp) habla JSON-RPC 2.0 y no usa este envoltorio.
Tipos y formatos
Fechas
Las fechas son YYYY-MM-DD; los instantes, ISO 8601 en UTC, por ejemplo 2026-10-01T08:00:00+00:00.
Números
Cantidades y montos son números JSON, no textos. Los montos van en la moneda de la cuenta (GET /tenant/currency).
Sin valor
Un campo sin valor suele llegar como null en lugar de omitirse.
Identificadores
Cadenas opacas con prefijo (sess_…, ds_…, sup_…): guárdalas tal cual.
Señales
El semáforo usa PEDIR_YA, PEDIR_PRONTO, OK y SOBRESTOCK: valores fijos que no se traducen.
Paginación
Hay tres formas, y cada endpoint la declara en sus parámetros:
skip y limit
Sesiones, resumen de sesiones, fuentes de datos y datasets. La respuesta trae items, total, skip y limit.
limit y offset
La actividad de alertas (/alerts/activity). La respuesta trae items, total, limit y offset.
solo limit
Los más recientes primero, hasta limit: alertas, historial de órdenes, brechas de configuración, mermas e historial de reentrenamientos.
sin paginación
El resto devuelve el conjunto completo y se acota con sus filtros, por ejemplo signal o supplier en /inventory/status.
Idempotencia
POST /inventory/log-po y POST /inventory/po aceptan la cabecera Idempotency-Key: un valor único (un UUID) por orden que quieres colocar. Si repites la petición con la misma clave recibes la orden que ya se creó (200 con replayed: true) en vez de una segunda; la misma clave con otras líneas responde 409 po_idempotency_key_reused. Los demás endpoints de escritura no son idempotentes: antes de reintentar una escritura cuyo resultado no viste, consulta si ya se aplicó.
La misma clave abre un servidor MCP en POST /mcp con cinco herramientas de solo lectura, para que un asistente de IA consulte tu semáforo. Por diseño no escribe nada. GET /mcp responde 405: el servidor no abre un flujo hacia el cliente.
Referencia de endpoints
Generada a partir del propio servicio: si un endpoint está aquí, se puede llamar con una API key. Las respuestas de ejemplo son llamadas reales a una cuenta de prueba. Las descripciones están en inglés, como el código.
POSTExplain a SKU's recommendation
Narrativas con IA
Explain a SKU's recommendation
POST/api/v1/ai/narrative/forecast-explanation
Clave de lecturaResponde 200 · application/json
Explains a specific SKU's inventory signal and recommendation in plain language.
Petición
Cabeceras
AuthorizationBearer sk_live_…obligatorio
Tu API key. Siempre obligatoria.
Content-Typeapplication/jsonobligatorio
Cuerpo
application/jsonEl cuerpo es obligatorio.
objectUn objeto.
skustringobligatorio
session_idstringobligatorio
profilestringopcionalpor defecto "distributor"
languagestringopcionalpor defecto "es"
Respuestas
200 Si sale bien
Para este endpoint no se capturó una respuesta de ejemplo. Toda respuesta JSON trae este envoltorio; lo que va en data depende del endpoint.
Errores posibles
Además de los errores de cada endpoint, toda llamada con clave puede responder:
401Authorization header missing, or API key invalid, revoked or expired.
403Key may not call this endpoint, is read-only on a write, or a permission check refused it.
429Per-minute limit or daily ceiling reached; honour Retry-After.
Return hyperparameter schemas for all available models.
Configuración de sesión
Dataset profile (alias)
GET/api/v1/sessions/{session_id}/profile
Clave de lecturaResponde 200 · application/json
Alias of GET /sessions/{session_id}/inspect.
Configuración de sesión
Upload and attach a dataset
POST/api/v1/sessions/{session_id}/upload
Clave de escrituraResponde 201 · application/json
Uploads a file (multipart) and attaches it to the session in one call.
Moneda
Read the currency
GET/api/v1/tenant/currency
Clave de lecturaResponde 200 · application/json
Readable by every role: it is needed to render any figure on any screen.
Fuentes de datos
List data sources
GET/api/v1/data-sources
Clave de lecturaResponde 200 · application/json
The tenant's file and SQL data sources. Paginated with skip and limit.
Fuentes de datos
Create a file data source
POST/api/v1/data-sources/file
Clave de escrituraResponde 200 · application/json
Uploads a CSV/Excel file (multipart) as a new data source.
Fuentes de datos
Create a SQL data source
POST/api/v1/data-sources/sql
Clave de escrituraResponde 200 · application/json
Registers a database connection as a data source. Fields may come from a pasted `connection_string` (URL, JDBC, ADO.NET or libpq form); typed fields win. `ssl_mode` is disable, prefer, require, verify-ca or verify-full; `ssl_ca` is the server's CA certificate (PEM), stored encrypted like the password. Private and link-local hosts are refused unless the installation allows them (`data_source_host_not_allowed`).
Fuentes de datos
Parse a connection string
POST/api/v1/data-sources/sql/parse
Clave de escrituraResponde 200 · application/json
Reads a connection string into engine, host, port, database, user and TLS mode. The password is never returned, only `has_password`.
Fuentes de datos
Delete a data source
DEL/api/v1/data-sources/{source_id}
Clave de escrituraResponde 200 · application/json
Removes the data source.
Fuentes de datos
Get a data source
GET/api/v1/data-sources/{source_id}
Clave de lecturaResponde 200 · application/json
One data source's metadata.
Fuentes de datos
Rename a data source
PATCH/api/v1/data-sources/{source_id}
Clave de escrituraResponde 200 · application/json
Changes the data source's name and description.
Fuentes de datos
Analyze a data source
GET/api/v1/data-sources/{source_id}/analyze
Clave de lecturaResponde 200 · application/json
Demand statistics over the source: totals, seasonality and per-SKU summaries, optionally within a date range.
Executes ONE read statement (SELECT or WITH ... SELECT) on the customer's database, inside a read-only transaction that is always rolled back, and returns up to `limit` rows starting at `offset`, with `has_more`. Needs a `write`-scope key: it runs caller-written SQL on the customer's database. Anything else is refused with `sql_multiple_statements`, `sql_not_a_select`, `sql_forbidden_keyword`, `sql_forbidden_function` or `sql_unsupported_syntax`.
Fuentes de datos
Export a SQL query as Excel or CSV
POST/api/v1/data-sources/{source_id}/export-query
Clave de escrituraResponde 200 · application/json
Runs the query (same read-only rules as execute-query) and returns the FULL result as an .xlsx (default) or .csv file, refusing rather than truncating past the row ceiling. Needs a `write`-scope key.
Fuentes de datos
Replace a data source's file
POST/api/v1/data-sources/{source_id}/file
Clave de escrituraResponde 200 · application/json
Uploads a new file (multipart) IN PLACE: the source keeps its id and column mapping, so the next training run needs no reconfiguration. The nightly-export endpoint.
Fuentes de datos
Materialize a SQL query as a dataset
POST/api/v1/data-sources/{source_id}/materialize
Clave de escrituraResponde 200 · application/json
Runs the query and stores the result as a dataset that sessions can train on.
Fuentes de datos
Preview a data source
GET/api/v1/data-sources/{source_id}/preview
Clave de lecturaResponde 200 · application/json
The first rows of the source (and of a given sheet, for Excel).
Fuentes de datos
Save a SQL source's query
PATCH/api/v1/data-sources/{source_id}/query
Clave de escrituraResponde 200 · application/json
Stores the query the SQL source materializes.
Fuentes de datos
Save an edited table as a new source
POST/api/v1/data-sources/{source_id}/save-as-new
Clave de escrituraResponde 200 · application/json
Creates a new data source from edited columns and rows.
Fuentes de datos
List a SQL source's tables
GET/api/v1/data-sources/{source_id}/schema
Clave de escrituraResponde 200 · application/json
Tables and views the connection can read, with row estimates and a safely quoted preview statement for each. Cached for a few minutes; `refresh=true` re-reads.
Column names, types and nullability of one table of a SQL source.
Fuentes de datos
Update a SQL source's connection
PATCH/api/v1/data-sources/{source_id}/sql-config
Clave de escrituraResponde 200 · application/json
Changes any connection field of a SQL source. Omitted fields keep their stored value, the password included, except when the engine, host or port changes: then the password must be sent again (`data_source_password_required`).
Runs a staged test (dns, tcp, tls, auth, privileges, select, tables) and reports each stage as ok, warning, failed or skipped with a code. Warns when the login can write, with the least-privilege GRANT statements.
Datasets
List datasets
GET/api/v1/datasets
Clave de lecturaResponde 200 · application/json
Uploaded datasets. Paginated with skip and limit.
Datasets
Upload a dataset
POST/api/v1/datasets
Clave de escrituraResponde 201 · application/json
Uploads a sales-history file (multipart) and profiles it.
Datasets
Get a dataset
GET/api/v1/datasets/{dataset_id}
Clave de lecturaResponde 200 · application/json
One dataset's metadata and profile.
Documentos
List documents
GET/api/v1/documents
Clave de lecturaResponde 200 · application/json
Documents uploaded for the analyst to read.
Documentos
Upload a document
POST/api/v1/documents
Clave de escrituraResponde 200 · application/json
Upload a document (PDF, DOCX, TXT up to 50 MB). File is saved to storage and indexed asynchronously. Returns doc metadata with status=PENDING immediately.
Documentos
Delete a document
DEL/api/v1/documents/{doc_id}
Clave de escrituraResponde 200 · application/json
Removes the document and its index.
Documentos
Get a document
GET/api/v1/documents/{doc_id}
Clave de lecturaResponde 200 · application/json
One document's metadata.
Documentos
Download a document
GET/api/v1/documents/{doc_id}/content
Clave de lecturaResponde 200 · application/json
Serve the raw file for in-browser viewing or download.
Documentos
Document indexing status
GET/api/v1/documents/{doc_id}/status
Clave de lecturaResponde 200 · application/json
Whether the document has been processed and indexed.
Plan y límites
Read plan and limits
GET/api/v1/entitlements
Clave de lecturaResponde 200 · application/json
This tenant's tier, its ceilings, and how close it is to them.
Pronósticos
Configuration schema
GET/api/v1/config/schema
Clave de lecturaResponde 200 · application/json
The JSON schema of every configuration block, independent of a session.
Pronósticos
Available forecasting models
GET/api/v1/models/available
Clave de lecturaResponde 200 · application/json
The forecasting models this deployment can train.
Pronósticos
Forecast accuracy
GET/api/v1/sessions/{session_id}/accuracy
Clave de lecturaResponde 200 · application/json
Accuracy of the session's forecasts against baselines, per SKU and overall.
The latest automatic reading of how this forecast is doing against the sales uploaded after it was made, next to its accuracy at training time.
Pronósticos
Models available to a session
GET/api/v1/sessions/{session_id}/available-models
Clave de lecturaResponde 200 · application/json
The models that can be trained on this session's data.
Pronósticos
Start Backtest
POST/api/v1/sessions/{session_id}/backtest
Clave de escrituraResponde 202 · application/json
Train a back-test of a completed session: the same configuration on a copy of its dataset with the last `holdout_periods` periods held out. Its forecast then covers those periods and can be graded against the full dataset with `forecast-vs-actual`. The source session and dataset are not modified; the run counts against the plan's saved-forecast ceiling and is refused (nothing deleted) when that is full.
Pronósticos
Session configuration schema
GET/api/v1/sessions/{session_id}/config-schema
Clave de lecturaResponde 200 · application/json
The configuration schema with this session's current values.
History and forecast (with quantiles) for one SKU, optionally for a given model.
Pronósticos
Get Forecast Total
GET/api/v1/sessions/{session_id}/forecast-total
Clave de lecturaResponde 200 · application/json
The whole catalogue as one series: every SKU's champion forecast and history summed per date. Feeds the session-comparison chart's "all SKUs" option, where two sessions are only comparable as totals.
What this session predicted vs. what the tenant's LATER sales uploads say actually happened: per-SKU and pooled WAPE / MAPE / bias, the predicted-vs- actual series, and a verdict code the frontend renders in words.
Pronósticos
Session inventory recommendations
GET/api/v1/sessions/{session_id}/inventory
Clave de lecturaResponde 200 · application/json
Per-SKU inventory recommendations computed from this session's forecast.
Pronósticos
Training metrics
GET/api/v1/sessions/{session_id}/metrics
Clave de lecturaResponde 200 · application/json
Validation metrics per model and SKU.
Pronósticos
List forecast overrides
GET/api/v1/sessions/{session_id}/overrides
Clave de lecturaResponde 200 · application/json
Manual adjustments made to the session's forecast.
Pronósticos
Save forecast overrides
PATCH/api/v1/sessions/{session_id}/overrides
Clave de escrituraResponde 200 · application/json
Upserts manual forecast values per SKU and date, with a reason. The body is a list.
Pronósticos
Predict on demand
POST/api/v1/sessions/{session_id}/predict
Clave de lecturaResponde 200 · application/json
Runs the trained model for one SKU with the given inputs and horizon.
Pronósticos
Data quality
GET/api/v1/sessions/{session_id}/quality
Clave de lecturaResponde 200 · application/json
Data-quality findings for the session's dataset.
Pronósticos
Reconcile actual values
POST/api/v1/sessions/{session_id}/reconcile
Clave de lecturaResponde 200 · application/json
Upload a CSV of actual values to compare against the stored forecast.
Pronósticos
Session report (alias)
GET/api/v1/sessions/{session_id}/report
Clave de lecturaResponde 200 · application/json
The session's results summarized as one report document.
Pronósticos
Training results
GET/api/v1/sessions/{session_id}/results
Clave de lecturaResponde 200 · application/json
Forecasts and per-model results of a completed session, at SKU or aggregate level.
Pronósticos
Model routing
GET/api/v1/sessions/{session_id}/routing
Clave de lecturaResponde 200 · application/json
Which model was routed to each SKU and why.
Pronósticos
Model routing plan (alias)
GET/api/v1/sessions/{session_id}/routing-plan
Clave de lecturaResponde 200 · application/json
The routing decisions as a plan, per SKU segment.
Pronósticos
Read a SKU's feature importances
GET/api/v1/sessions/{session_id}/shap/{sku}
Clave de lecturaResponde 200 · application/json
Return SHAP feature importances for the best model for the given SKU.
Everything known about one SKU in the session: series, model, drivers and recommendation.
Pronósticos
List run warnings
GET/api/v1/sessions/{session_id}/warnings
Clave de lecturaResponde 200 · application/json
Data problems the validation layers found while training this session.
Frescura de datos
Read data freshness
GET/api/v1/data-freshness
Clave de lecturaResponde 200 · application/json
Age of the sales history and of the stock table, plus whether the semáforo may still claim a colour.
Inventario, compras y proveedores
Send the daily alert now
POST/api/v1/inventory/alerts/send-now
Clave de escrituraResponde 202 · application/json
Fire the daily inventory alert immediately for this tenant — email to the admins, WhatsApp to the ones who opted in. Lets the user verify their channels without waiting for the 8:00 UTC scheduler run.
Inventario, compras y proveedores
List where a component is used
GET/api/v1/inventory/bom/{child_sku}/used-in
Clave de lecturaResponde 200 · application/json
Returns all finished goods that use this component.
Inventario, compras y proveedores
Read a bill of materials
GET/api/v1/inventory/bom/{parent_sku}
Clave de lecturaResponde 200 · application/json
Returns BOM (Bill of Materials) for a finished good.
Inventario, compras y proveedores
Remove a bill-of-materials line
DEL/api/v1/inventory/bom/{parent_sku}/{child_sku}
Clave de escrituraResponde 204 · application/json
Removes a component from a parent SKU's bill of materials.
Inventario, compras y proveedores
Set a bill-of-materials line
PUT/api/v1/inventory/bom/{parent_sku}/{child_sku}
Clave de escrituraResponde 200 · application/json
Creates or updates how much of a component one unit of the parent SKU uses.
Inventario, compras y proveedores
Import stock from a file
POST/api/v1/inventory/bulk
Clave de escrituraResponde 200 · application/json
Import stock from a CSV or Excel file.
Inventario, compras y proveedores
Preview a stock import
POST/api/v1/inventory/bulk/preview
Clave de escrituraResponde 200 · application/json
Dry run of POST /bulk: what we detected in the file and what we would write, without touching a single row. This is what makes the mapping wizard possible — the user corrects our column guesses BEFORE importing, the same way the sales upload works.
Inventario, compras y proveedores
Read the cash calendar
GET/api/v1/inventory/cash-calendar
Clave de lecturaResponde 200 · application/json
Invoices falling due from POs already sent, dated by each supplier's credit terms. Read-only, so viewers may call it.
Inventario, compras y proveedores
Fit a purchase into a budget
POST/api/v1/inventory/cash-calendar/fit
Clave de lecturaResponde 200 · application/json
"Does the recommended purchase fit in the cash I have?"
Inventario, compras y proveedores
Read the dashboard summary
GET/api/v1/inventory/dashboard-summary
Clave de lecturaResponde 200 · application/json
Lightweight endpoint for the dashboard widget. Returns only the summary counts without the full item list.
Inventario, compras y proveedores
List dead capital
GET/api/v1/inventory/dead-capital
Clave de lecturaResponde 200 · application/json
Every SKU on hand whose stock level has not fallen in at least `window_days`, ranked worst first by money, with the tenant's total at the top. Needs no session — it reads real stock-level history, not a forecast.
Inventario, compras y proveedores
List demand events
GET/api/v1/inventory/events
Clave de lecturaResponde 200 · application/json
Promotions and seasonal events that multiply expected demand.
Inventario, compras y proveedores
Create a demand event
POST/api/v1/inventory/events
Clave de escrituraResponde 201 · application/json
Adds an event with a date range and a demand multiplier.
Inventario, compras y proveedores
Read the event catalog
GET/api/v1/inventory/events/catalog
Clave de lecturaResponde 200 · application/json
Which commercial events StockAI knows for a country, and whether this tenant has them seeded / switched on. Read-only.
Inventario, compras y proveedores
Seed the event catalog
POST/api/v1/inventory/events/catalog/seed
Clave de escrituraResponde 200 · application/json
Preload the LatAm commercial calendar into this tenant's events.
Drop the override: the product falls back to the event multiplier.
Inventario, compras y proveedores
Project revenue, cost and margin
GET/api/v1/inventory/forecast-money
Clave de lecturaResponde 200 · application/json
Projected revenue, cost and gross margin over the active session's forecast horizon, per SKU and in total, ranked so the top contributors are visible — "your next N days: X in sales, Y in margin, and these products carry it."
Inventario, compras y proveedores
Record a purchase order
POST/api/v1/inventory/log-po
Clave de escrituraResponde 201 · application/json
Records that an order was placed, with its lines. Reception tracking and supplier lead-time learning read it. A body without `items` records every actionable SKU of the session.
Inventario, compras y proveedores
List margin erosion
GET/api/v1/inventory/margin-erosion
Clave de lecturaResponde 200 · application/json
SKUs whose margin eroded because their cost rose while the product's sale_price is the only price StockAI has ever stored. `price_history_available: false` in the response is load-bearing: the "before" margin is today's price against a past cost, not a historical fact — see `cost_alerts.get_margin_erosion`'s docstring.
Inventario, compras y proveedores
Read the morning briefing
GET/api/v1/inventory/morning-briefing
Clave de lecturaResponde 200 · application/json
Daily operations briefing: risks, recommendations, demand changes, KPIs. Designed to be the first thing a manager opens every morning. Reflects the tenant's ACTIVE planning period — coverage and the signal in that unit — so /hoy agrees with /inventory (a weekly session must be read as weekly).
Inventario, compras y proveedores
Optimize purchases and transfers
GET/api/v1/inventory/optimize
Clave de lecturaResponde 200 · application/json
Runs the MILP purchasing/transfers optimizer for this session and returns suggested purchase quantities per SKU x warehouse, plus recommended inter-warehouse transfers, collapsed to one total per line over the full horizon.
Inventario, compras y proveedores
Create a manual purchase order
POST/api/v1/inventory/po
Clave de escrituraResponde 201 · application/json
A purchase order the buyer writes from scratch — supplier chosen explicitly, lines typed in, no forecast session behind it. Persisted with source='manual' so adoption metrics stay clean. `Idempotency-Key`: same contract as /log-po.
Inventario, compras y proveedores
List recent purchase orders
GET/api/v1/inventory/po-history
Clave de lecturaResponde 200 · application/json
Returns recent PO generation events for the history panel.
Inventario, compras y proveedores
Po History Page
GET/api/v1/inventory/po-history/page
Clave de lecturaResponde 200 · application/json
The PO history, filtered and paged on the server. `total` counts the filtered set; `awaiting_reception` counts every open order of the tenant.
Inventario, compras y proveedores
Import purchase orders from a file
POST/api/v1/inventory/po/import
Clave de escrituraResponde 200 · application/json
Create purchase orders from a CSV / Excel file, one order per (order reference, supplier, destination warehouse).
Inventario, compras y proveedores
Preview a purchase-order import
POST/api/v1/inventory/po/import/preview
Clave de escrituraResponde 200 · application/json
Dry run of POST /po/import: the orders the file would create, and every row whose supplier / product / warehouse did not resolve. Writes nothing.
Inventario, compras y proveedores
Download the purchase-order import template
GET/api/v1/inventory/po/import/template
Clave de lecturaResponde 200 · application/json
Purchase-order import template: header row plus example lines (two orders, the first with two lines).
Inventario, compras y proveedores
List overdue purchase orders
GET/api/v1/inventory/po/overdue
Clave de lecturaResponde 200 · application/json
POs still pending/partial whose expected arrival — order date plus the supplier's already-learned lead time — has passed with no reception recorded. Powers the /hoy 'did it arrive?' nudge.
Inventario, compras y proveedores
List a purchase order's lines
GET/api/v1/inventory/po/{po_log_id}/items
Clave de lecturaResponde 200 · application/json
Lines of a PO with ordered vs received quantities (reception form).
Inventario, compras y proveedores
Receive a purchase order
POST/api/v1/inventory/po/{po_log_id}/receive
Clave de escrituraResponde 200 · application/json
Record that a PO arrived (fully, partially, or not at all). Side effects: current_stock increases by the received units, and StockAI logs the supplier's REAL lead time (order date → reception date).
Inventario, compras y proveedores
Send a purchase order to suppliers
POST/api/v1/inventory/po/{po_log_id}/send
Clave de escrituraResponde 200 · application/json
Sends a PO's PDF to each of its suppliers by email and WhatsApp, grouping the PO's lines by supplier name (a PO can span more than one supplier). Lines with no supplier name, or whose supplier has no saved contact info, are skipped and reported back — never a 500.
Inventario, compras y proveedores
List price breaks
GET/api/v1/inventory/price-breaks
Clave de lecturaResponde 200 · application/json
Supplier quantity scales, optionally filtered by supplier and/or SKU.
Inventario, compras y proveedores
Evaluate price breaks for a cart
POST/api/v1/inventory/price-breaks/evaluate
Clave de lecturaResponde 200 · application/json
Given the cart the buyer currently has on screen, which lines are one step away from a better unit price AND would still be a good idea to step up to.
The valid product types, as the English keys the frontend translates.
Inventario, compras y proveedores
Explode demand into components
GET/api/v1/inventory/production-requirements
Clave de lecturaResponde 200 · application/json
MRP Level 1 explosion: given forecast demand + BOM, returns required quantities of each component and raw material, flagging shortages and purchase requirements.
Inventario, compras y proveedores
Download the inventory PDF
GET/api/v1/inventory/report/pdf
Clave de lecturaResponde 200 · application/json
Generates and streams a one-page executive PDF inventory summary.
Inventario, compras y proveedores
Read accumulated ROI
GET/api/v1/inventory/roi
Clave de lecturaResponde 200 · application/json
Returns accumulated ROI metrics across all time.
Inventario, compras y proveedores
Read one month's ROI report
GET/api/v1/inventory/roi/month-report
Clave de lecturaResponde 200 · application/json
Recap of a single calendar month (feature 3.2). Defaults to the month that just closed — the same period the monthly recap email covers.
Inventario, compras y proveedores
List monthly ROI
GET/api/v1/inventory/roi/monthly
Clave de lecturaResponde 200 · application/json
Last N months: orders, stockout risks handled, adoption, capital freed from overstock.
Inventario, compras y proveedores
List SKUs missing setup
GET/api/v1/inventory/setup-gaps
Clave de lecturaResponde 200 · application/json
Unconfigured SKUs ordered by the money they move, with the running cumulative share of projected spend.
Inventario, compras y proveedores
List shrinkage
GET/api/v1/inventory/shrinkage
Clave de lecturaResponde 200 · application/json
Recent history of recorded shrinkage (input to the future monthly summary).
Inventario, compras y proveedores
Record shrinkage
POST/api/v1/inventory/shrinkage
Clave de escrituraResponde 201 · application/json
Record a stock-out that is NOT a sale — breakage, expiry, self-consumption or a gift/sample. Decrements the SKU's theoretical stock through the same path PO reception uses (so the signal stays accurate) and accumulates the cost (quantity x unit cost) for a future monthly shrinkage summary.
Inventario, compras y proveedores
List shrinkage reasons
GET/api/v1/inventory/shrinkage/reasons
Clave de lecturaResponde 200 · application/json
Returns the valid shrinkage reason codes (labels are handled client-side via i18n).
Inventario, compras y proveedores
Read the inventory traffic light
GET/api/v1/inventory/status
Clave de lecturaResponde 200 · application/json
Returns per-SKU inventory status in the tenant's ACTIVE planning period:
- coverage (in the active period's units — see `coverage_unit`)
- traffic-light signal (PEDIR_YA / PEDIR_PRONTO / OK / SOBRESTOCK / SIN_DATOS)
- recommended order quantity
- inventory value
Inventario, compras y proveedores
Export the purchase order as CSV
GET/api/v1/inventory/status/export-po
Clave de lecturaResponde 200 · application/json
Export purchase order as CSV, filtered to actionable SKUs.
Inventario, compras y proveedores
List stock
GET/api/v1/inventory/stock
Clave de lecturaResponde 200 · application/json
Every SKU's stock record: on hand, minimum, lead time, cost, supplier and catalogue fields.
Inventario, compras y proveedores
List Counts
GET/api/v1/inventory/stock-counts
Clave de lecturaResponde 200 · application/json
List stock counts, newest first, with how many products each holds.
Inventario, compras y proveedores
Create Count
POST/api/v1/inventory/stock-counts
Clave de escrituraResponde 201 · application/json
Open a count session for one warehouse, optionally scoped to a category or supplier.
Inventario, compras y proveedores
Get Count
GET/api/v1/inventory/stock-counts/{count_id}
Clave de lecturaResponde 200 · application/json
One count with every line (counted quantity next to the system quantity at the first scan).
Write the differences into stock, exactly once, and record each adjustment with reason 'physical_count'. Omit skus to apply every line; a list applies only those. All or nothing.
Sets the supplier's cost, MOQ, lead time and primary flag for the SKU.
Inventario, compras y proveedores
List supplier cost inflation
GET/api/v1/inventory/supplier-cost-inflation
Clave de lecturaResponde 200 · application/json
Suppliers who raised a SKU's cost at least once in the window, worst first, with the products each one hit hardest. Built only from POs that were actually received — a quoted or rejected order proves nothing was paid.
Inventario, compras y proveedores
List suppliers
GET/api/v1/inventory/suppliers
Clave de lecturaResponde 200 · application/json
The tenant's suppliers with contact details, lead times and payment terms.
Inventario, compras y proveedores
Create a supplier
POST/api/v1/inventory/suppliers
Clave de escrituraResponde 201 · application/json
Adds a supplier with contact details, lead time and payment terms.
Inventario, compras y proveedores
Check supplier contact details
GET/api/v1/inventory/suppliers/contact-health
Clave de lecturaResponde 200 · application/json
Suppliers that POST /po/{id}/send would silently skip — no email and no WhatsApp on file, or a supplier name on PO lines with no record at all (feature 2.5).
Inventario, compras y proveedores
Import suppliers from a file
POST/api/v1/inventory/suppliers/import
Clave de escrituraResponde 200 · application/json
Create suppliers from a CSV / Excel file.
Inventario, compras y proveedores
Preview a suppliers import
POST/api/v1/inventory/suppliers/import/preview
Clave de escrituraResponde 200 · application/json
Dry run of POST /suppliers/import: what was detected and what would be written. Touches no row.
Inventario, compras y proveedores
Download the suppliers import template
GET/api/v1/inventory/suppliers/import/template
Clave de lecturaResponde 200 · application/json
Suppliers import template: the header row plus two example rows.
Inventario, compras y proveedores
List supplier lead-time alerts
GET/api/v1/inventory/suppliers/lead-time-alerts
Clave de lecturaResponde 200 · application/json
Suppliers whose recent lead time is significantly slower than their own history — "Acme is taking 12 days, not 7" (feature 3.3).
Inventario, compras y proveedores
List Suppliers Page
GET/api/v1/inventory/suppliers/page
Clave de lecturaResponde 200 · application/json
Active suppliers, searched and paged on the server (the plain list stays whole for the dropdowns that need every supplier).
Inventario, compras y proveedores
Read the supplier scorecard
GET/api/v1/inventory/suppliers/scorecard
Clave de lecturaResponde 200 · application/json
Per-supplier performance: real lead time range, on-time rate, fill rate.
Inventario, compras y proveedores
Deactivate a supplier
DEL/api/v1/inventory/suppliers/{supplier_id}
Clave de escrituraResponde 204 · application/json
Deactivates the supplier (see the reactivate endpoint).
Inventario, compras y proveedores
Update a supplier
PATCH/api/v1/inventory/suppliers/{supplier_id}
Clave de escrituraResponde 200 · application/json
Changes a supplier's contact details, lead time, review period or payment terms.
Records the quantities that arrived at the destination warehouse.
Inventario, compras y proveedores
List warehouses
GET/api/v1/inventory/warehouses
Clave de lecturaResponde 200 · application/json
The tenant's warehouses.
Inventario, compras y proveedores
Create a warehouse
POST/api/v1/inventory/warehouses
Clave de escrituraResponde 201 · application/json
Adds a warehouse, optionally as the default.
Inventario, compras y proveedores
Delete a transfer lane
DEL/api/v1/inventory/warehouses/lanes
Clave de escrituraResponde 204 · application/json
Names travel as query params, not path segments: a warehouse name may contain a slash and would break path matching once encoded.
Inventario, compras y proveedores
List transfer lanes
GET/api/v1/inventory/warehouses/lanes
Clave de lecturaResponde 200 · application/json
Configured lanes only. A pair with no row falls back to the documented default (lead_time_days=1, cost_per_unit=0, fixed_cost=0) everywhere it is consumed — see backend/inventory/transfer_lane_service.py.
Inventario, compras y proveedores
Set a transfer lane
PUT/api/v1/inventory/warehouses/lanes
Clave de escrituraResponde 200 · application/json
Creates or updates the lead time and costs of moving stock between two warehouses.
Inventario, compras y proveedores
Update a warehouse
PATCH/api/v1/inventory/warehouses/{name}
Clave de escrituraResponde 200 · application/json
Set or clear the manual demand share for one warehouse (feature 5.4).
Every SKU that carried an ordering signal (PEDIR_YA/PEDIR_PRONTO) in the window: whether a purchase order followed, and — only where it did not and stock was later observed at or below zero — the estimated unserved units and their value. See `recommendation_reports.cost_of_ignoring` for the conservatism rules (no PO + no observed stockout => no loss claimed; no sale price => units reported, value null).
The SKU's latest recorded recommendation against the previous recorded one, decomposed into avg daily demand, lead time, stock on hand and safety stock — each tagged with whether it came from a new training session (a model opinion) or the tenant's own operational data. Returns `available: false` with a `reason` when there is not yet a previous row to compare against.
Reversas de órdenes
Undo a purchase-order reception
POST/api/v1/inventory/po/{po_log_id}/unreceive
Clave de escrituraResponde 200 · application/json
Undo a reception: take the received units back out of stock, reset the PO line's `received_qty` and the order's `reception_status`, and remove the lead-time observation(s) that reception taught the supplier scorecard. Refuses (409, with the offending SKU/warehouse named) rather than go negative if some of the received units are no longer in stock. See `reception_service.unreceive_po` for the full reasoning.
Reversas de órdenes
Undo marking a purchase order as sent
POST/api/v1/inventory/po/{po_log_id}/unsend
Clave de escrituraResponde 200 · application/json
Undo `mark_po_sent`: clear `sent_at` so the order stops counting as incoming stock and drops off the cash-payables calendar. Does NOT recall the email/WhatsApp message a prior `/send` may have delivered — that left the system and nothing can pull it back. Refuses once a reception exists against this PO (undo that first). See `reception_service.unsend_po`.
MCP (clientes de IA)
Call the MCP server (JSON-RPC)
POST/api/v1/mcp
Clave de lecturaResponde 200 · application/json
Model Context Protocol endpoint, for an AI client the customer runs.
Planificación
Planning context
GET/api/v1/planning
Clave de lecturaResponde 200 · application/json
The active planning period and `active_session_id` — the session the app's own screens show.
Run a saved scenario and return the BASE vs SCENARIO comparison.
Reentrenamiento programado
List retraining schedules
GET/api/v1/schedules
Clave de lecturaResponde 200 · application/json
Every schedule this tenant has, with the session's name.
Reentrenamiento programado
List scheduler history
GET/api/v1/schedules/history
Clave de lecturaResponde 200 · application/json
What the scheduler has actually done, newest first.
Reentrenamiento programado
Delete a retraining schedule
DEL/api/v1/sessions/{session_id}/schedule
Clave de escrituraResponde 200 · application/json
Stops the session's scheduled retraining.
Reentrenamiento programado
Get a retraining schedule
GET/api/v1/sessions/{session_id}/schedule
Clave de lecturaResponde 200 · application/json
The session's cron schedule for automatic retraining.
Reentrenamiento programado
Save a retraining schedule
POST/api/v1/sessions/{session_id}/schedule
Clave de escrituraResponde 200 · application/json
Sets a cron expression for automatic retraining, and whether it is enabled.
Sesiones
List sessions
GET/api/v1/sessions
Clave de lecturaResponde 200 · application/json
Forecast sessions with their state. Paginated with skip and limit.
Sesiones
Create a session
POST/api/v1/sessions
Clave de escrituraResponde 201 · application/json
Creates a forecast session in DRAFT.
Sesiones
List session summaries
GET/api/v1/sessions/summary
Clave de lecturaResponde 200 · application/json
The sessions library: every session of the tenant, enriched (dataset name, horizon, SKU count, granularity, headline accuracy, models), searchable, filterable, sortable and paginated. `total` counts the rows matching the filters, so a pager can be drawn.
Sesiones
Delete a session
DEL/api/v1/sessions/{session_id}
Clave de escrituraResponde 204 · application/json
Deletes the session and its results.
Sesiones
Get a session
GET/api/v1/sessions/{session_id}
Clave de lecturaResponde 200 · application/json
One session's metadata and state.
Sesiones
Update a session
PATCH/api/v1/sessions/{session_id}
Clave de escrituraResponde 200 · application/json
Changes a session's name, description or tags.
Sesiones
Get Manifest
GET/api/v1/sessions/{session_id}/manifest
Clave de lecturaResponde 200 · application/json
How this forecast was produced: who or what started the run, the dataset's content hash and size, the full configuration, engine and library versions, per-model outcomes, stage timings and a hash of the forecast. Written once when the run ends and never changed. 404 `manifest_not_available` for a session that has not finished a run since manifests were introduced.
Sesiones
Restore Session
POST/api/v1/sessions/{session_id}/restore
Clave de escrituraResponde 200 · application/json
Bring an archived session back into the working list. Counts against the plan's saved-forecast ceiling like a new one: at the ceiling it is refused with the same message, and the session stays archived and intact.
Sesiones
Get Run Durations
GET/api/v1/training/run-durations
Clave de lecturaResponde 200 · application/json
Median and p95 training duration over the tenant's last `limit` runs, by catalogue-size bucket and by granularity, read from the lineage manifests (no new storage). For choosing a retrain cadence from evidence.
Zona horaria
Read the time zone
GET/api/v1/tenant/timezone
Clave de lecturaResponde 200 · application/json
Readable by every role: any screen showing a scheduled time needs it.
Entrenamiento
List active jobs
GET/api/v1/jobs/active
Clave de lecturaResponde 200 · application/json
Training runs of this tenant that are queued or running right now.
Entrenamiento
Cancel a job
DEL/api/v1/jobs/{job_id}
Clave de escrituraResponde 200 · application/json
Cancels a queued or running training job.
Entrenamiento
Get a job
GET/api/v1/jobs/{job_id}
Clave de lecturaResponde 200 · application/json
A training job's state and progress.
Entrenamiento
Job logs
GET/api/v1/jobs/{job_id}/logs
Clave de lecturaResponde 200 · application/json
The last `tail` log lines of a training job.
Entrenamiento
List a session's jobs
GET/api/v1/sessions/{session_id}/jobs
Clave de lecturaResponde 200 · application/json
Training jobs run for the session.
Entrenamiento
Start Reforecast
POST/api/v1/sessions/{session_id}/reforecast
Clave de escrituraResponde 202 · application/json
Create a NEW session that forecasts from this session's stored models over newer sales, without retraining. The source session is never modified. Counts against the plan's saved-forecast ceiling; runs on the job queue.
Whether a re-forecast with newer sales is on offer for this session: stored models present, newer data than the forecast used, and the refit age of the models. `reason` is a stable code when it is not.
Entrenamiento
Start training
POST/api/v1/sessions/{session_id}/train
Clave de escrituraResponde 202 · application/json
Queues a training run for a configured session. Poll /sessions/{session_id}/train/status.
Entrenamiento
Read training status
GET/api/v1/sessions/{session_id}/train/status
Clave de lecturaResponde 200 · application/json
Returns the latest job status for this session. Alias used by the Frontend — maps to GET /jobs/{job_id} for the most recent job.
Webhooks
List webhooks
GET/api/v1/webhooks
Clave de lecturaResponde 200 · application/json
Outgoing webhooks and the events they subscribe to.
Webhooks
Create a webhook
POST/api/v1/webhooks
Clave de escrituraResponde 200 · application/json
Subscribes an https URL to business events (purchase orders, stockouts, commitments, jobs). The signing secret is returned once.
Webhooks
List webhook events
GET/api/v1/webhooks/events
Clave de lecturaResponde 200 · application/json
The events a webhook can subscribe to and the data keys each carries.
Webhooks
Delete a webhook
DEL/api/v1/webhooks/{webhook_id}
Clave de escrituraResponde 200 · application/json
Removes the webhook and its delivery log.
Webhooks
List webhook deliveries
GET/api/v1/webhooks/{webhook_id}/deliveries
Clave de lecturaResponde 200 · application/json
The delivery log: status, attempts, last status code, last error and next retry.
Webhooks
Re-enable a webhook
POST/api/v1/webhooks/{webhook_id}/enable
Clave de escrituraResponde 200 · application/json
Switches a webhook back on after it was disabled for repeated failures.
Webhooks
Rotate a webhook secret
POST/api/v1/webhooks/{webhook_id}/rotate-secret
Clave de escrituraResponde 200 · application/json
Issues a new signing secret, returned once. The old one stops verifying at once.
Webhooks
Send a test event
POST/api/v1/webhooks/{webhook_id}/test
Clave de escrituraResponde 200 · application/json
Queues a signed webhook.test delivery to the webhook.
Petición
curl-X POST "$STOCKAI/ai/narrative/forecast-explanation"\-H"Authorization: Bearer $STOCKAI_KEY"\-H"Content-Type: application/json"\-d'{"sku":"SKU-001","session_id":"<session_id>","profile":"distributor","language":"es"}'