Python and TypeScript clients
Two single-file clients with no dependencies, generated from the API itself: how to install them, build the client, make calls and handle errors.
The clients are in StockAI's source code: sdk/python/stockai_client.py and sdk/typescript/stockai-client.ts. They are generated from the API's description, with one method per endpoint, and a test fails if they drift from it.
Installing
- Python
- Copy
stockai_client.pynext to your code. It uses only the standard library: there is no package to install. - TypeScript / JavaScript
- Copy
stockai-client.tsinto your project. It usesfetch, so it works on Node 18+, Deno, Bun and browsers.
Python
# Copy sdk/python/stockai_client.py next to your code. Standard library only.
from stockai_client import StockAI, StockAIError
api = StockAI("sk_live_...") # base_url="https://app.stockai.es" by default
# api = StockAI(key, base_url="https://stockai.yourcompany.com", timeout=60.0)
planning = api.get_planning()["data"] # every call returns the full envelope
session = planning["active_session_id"]
urgent = api.get_inventory_status(signal="PEDIR_YA")["data"]["items"]
try:
api.post_inventory_log_po(
session_id=session,
idempotency_key="6f1c2a0e-1b7d-4c55-9a51-3f0f4e0b8d21",
body={"items": [{"sku": "SKU-001", "recommended_qty": 120,
"final_qty": 100, "status": "modified"}]},
)
except StockAIError as e:
print(e.status, e.error_code, e.error_params, e.retry_after)
# A file upload
with open("sales.csv", "rb") as f:
api.post_data_sources_source_id_file("ds_66dede3ccf04",
files={"file": ("sales.csv", f.read())})TypeScript
// Copy sdk/typescript/stockai-client.ts into your project. No dependencies (fetch only).
import { StockAI, StockAIError } from './stockai-client'
const api = new StockAI(process.env.STOCKAI_KEY!) // or new StockAI(key, 'https://stockai.yourcompany.com')
const planning = (await api.get_planning()).data
const urgent = (await api.get_inventory_status({ signal: 'PEDIR_YA' })).data.items
try {
await api.post_inventory_log_po({
session_id: planning.active_session_id,
'Idempotency-Key': crypto.randomUUID(),
body: { items: [{ sku: 'SKU-001', recommended_qty: 120, final_qty: 100, status: 'modified' }] },
})
} catch (e) {
if (e instanceof StockAIError) console.log(e.status, e.errorCode, e.errorParams, e.retryAfter)
}How methods are named
- The name is the HTTP method plus the path:
GET /inventory/status→get_inventory_status;POST /purchase-orders/{po_log_id}/erp-reference→post_purchase_orders_po_log_id_erp_reference. It is the same id as in the /desarrolladores reference. - Path parameters come first, positional; query parameters by name (Python) or in an object (TypeScript).
- Every call returns the full envelope as the API sent it (
success,data,meta); a file download returns the bytes. - The constructor refuses a key that does not start with
sk_. The default URL ishttps://app.stockai.es; for your own installation, pass it as the second argument.
Errors
A refused call throws StockAIError with the HTTP status (status), the error_code, the error_params and, when the API sent one, retry_after (Python) / retryAfter (TypeScript) in seconds. The clients do not retry on their own: apply the rules in Limits and errors.
When a method is not enough
Both clients have a generic request(method, path, ...). Use it for the routes that read the raw body, such as pushing rows to a sync profile or applying a profile document: the generated post_inventory_sync_profiles_profile_id_ingest and post_inventory_sync_profiles_apply methods take no body.
# Python: push rows through the generic request() (the generated ingest method sends no body)
api.request("POST", f"/inventory-sync/profiles/{profile_id}/ingest",
body={"batch_id": "night-2026-10-22", "rows": rows})
// TypeScript
await api.request('POST', '/inventory-sync/profiles/' + profileId + '/ingest',
{ body: { batch_id: 'night-2026-10-22', rows } })