# Pura LLM — API 2026-10-01 # SDK quick start (React, Node, Python) Allow about 10 minutes after registering your integration app in Pura. An active paid subscription and enabled chat service are required for inference. Register an exact **HTTPS** callback URI; plain localhost callbacks are rejected. Use a local HTTPS development endpoint or registered HTTPS development host. Version 0.1.0 targets API `2026-10-01`. Publication status and local artifact installation are in [release verification](https://platform.puradigital.it/en/developers/testing). After publication: `npm install @pura-ai/sdk` or `pip install pura-llm-sdk`. ## Run the complete single-user demo Set `PURA_CLIENT_ID`, `PURA_REDIRECT_URI` and, for a confidential app, `PURA_CLIENT_SECRET` in your shell. The callback must already be registered and served via HTTPS. Open the generated authorization URL, approve consent and paste the full callback URL into the terminal within ten minutes. The examples exchange the code, call capabilities/chat and display usage without printing tokens. Chat consumes your test account’s subscription allowance. Tokens live in memory only; rerun to reconnect. ```sh node packages/pura-sdk/examples/connect.mjs # Or, with the Python SDK installed: python packages/pura-sdk-python/examples/connect.py ``` ## Node: connect → tokens → chat → usage ```ts import {createAuthorization, PuraOAuthClient, PuraInferenceClient, type StoredTokens} from '@pura-ai/sdk'; const options = { apiBase: process.env.PURA_API_BASE || 'https://ai.puradigital.it/v1', clientId: process.env.PURA_CLIENT_ID!, clientSecret: process.env.PURA_CLIENT_SECRET!, // confidential backend only }; const redirectUri = process.env.PURA_REDIRECT_URI!; const {url, pending} = await createAuthorization({...options, redirectUri}); // Persist pending in the authenticated user's session; redirect their browser to url. // In that user's callback handler, callbackUrl is the full incoming HTTPS URL: // const tokens = await new PuraOAuthClient(options).exchange(callbackUrl, pending); // Validate and save tokens.pura_user_id against the authenticated local account. // A runnable in-memory demo store; reconnect after process restart. // Production must use encrypted per-user persistence with a shared refresh lock. let saved: StoredTokens | null = null; const store = {get: async () => saved, set: async (value: StoredTokens) => {saved = value;}}; // await store.set(tokens); // after the callback exchange above const pura = new PuraInferenceClient({...options, store}); // Once connected: // console.log(await pura.chat({messages: [{role: 'user', content: 'Hello'}]})); // console.log(await pura.usage()); ``` The code exchange is run only on the callback, not immediately after generating `url`. Server applications must persist `pending` across these two requests. ## Python: same callback lifecycle ```python import os from pura_llm import create_authorization, PuraOAuthClient, PuraInferenceClient options = dict(api_base=os.getenv('PURA_API_BASE', 'https://ai.puradigital.it/v1'), client_id=os.environ['PURA_CLIENT_ID'], client_secret=os.environ['PURA_CLIENT_SECRET']) url, pending = create_authorization(**{k: v for k, v in options.items() if k != 'client_secret'}, redirect_uri=os.environ['PURA_REDIRECT_URI']) # Persist pending in the local user's session and redirect to url. class DemoStore: def __init__(self): self.tokens = None def get(self): return self.tokens def set(self, tokens): self.tokens = tokens store = DemoStore() # demo only: one connected user in one process # In the authenticated callback handler: # oauth = PuraOAuthClient(**options) # try: store.set(oauth.exchange(callback_url, pending)) # finally: oauth.close() # After connection: # pura = PuraInferenceClient(**options, store=store) # try: # print(pura.chat(messages=[{'role': 'user', 'content': 'Hello'}])) # print(pura.usage()) # finally: pura.close() ``` ## React Use a registered public client with PKCE and no client secret. See the [complete React example](https://platform.puradigital.it/en/docs/integrations/react) for Connect and callback code. For confidential/BFF applications keep OAuth tokens and exchanges on the server; the browser's UsagePanel can receive a `client` adapter whose `usage()` calls your own authenticated usage endpoint. ## Behavior and errors SDK exchange validates state, callback and the ten-minute pending lifetime. Access tokens refresh before expiration and once on HTTP 401. Persist every rotation. Multi-worker stores must implement `withRefreshLock` (TypeScript) or `with_refresh_lock` (Python), bound to the same user's grant and transaction. A reused refresh token revokes its family. See the SDK README for the adapter contract. Inference omits `model`; capabilities report enabled chat/audio services. Usage contains monthly/weekly used and remaining percentages and reset dates, never monetary budgets. `PuraError.status/code` identifies missing connection (401), subscription limits (402), concurrency limits (429), or unavailable service (503). No wallet fallback. Audio availability requires server configuration. Canonical: https://platform.puradigital.it/en/docs/integrations/sdk.