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.
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.
node packages/pura-sdk/examples/connect.mjs
# Or, with the Python SDK installed:
python packages/pura-sdk-python/examples/connect.pyNode: connect → tokens → chat → usage
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
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 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.