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.

On this page
  1. Installing
  2. Python
  3. TypeScript
  4. How methods are named
  5. Errors
  6. When a method is not enough

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.py next to your code. It uses only the standard library: there is no package to install.
TypeScript / JavaScript
Copy stockai-client.ts into your project. It uses fetch, 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 is https://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 } })