Python SDK
Status: not published yet.
nexspace is generated by
Stainless from the merged OpenAPI spec and
stainless.config.yml; the first release has not landed on PyPI. The
hand-written package under packages/sdk-python/ is a deprecated stopgap
carrying the Private :: Do Not Upload classifier so it can never be uploaded
over the canonical package — it is not what this page documents. Track
tools/stainless/README.md
for the release.Installation
Quick Start
Configuration
There is no
version argument. NexSpace-Version is a per-request header
(see Pinning an API version), not a constructor
argument — a client-level default would silently pin every caller in your
process to one date.Resources
The generated resources mirrorstainless.config.yml. Path parameters are
positional; query and body fields are keyword arguments in snake_case.
Facilities
update needs facilities:write. create is guarded by role, not scope —
authorize(ROLES.SUPER_ADMIN) against the key owner’s role — so it only
succeeds for a key owned by a super admin.
Staff
GET /api/staff accepts exactly four filters — facility_id, specialty,
is_active, and search (name or email). There is no query field and no
limit.
Staff credentials
Credentials hang off a staff member, as thestaff.credentials subresource:
status — one of active, expiring, expired,
pending, rejected — so filter client-side on that plus expiration_date to
find what is lapsing. There is no server-side “expiring credentials” REST
endpoint; the MCP verb listExpiringCredentials covers that shape over
MCP.
Shifts
status accepts open, assigned, in_progress, completed, or
cancelled. shifts.unassign and shifts.delete are generated too.
Agent runs
agents:run scope. A second concurrent start for the same agent
returns 409 AGENT_BUSY. agents.list_runs, agents.cancel_run, and
agents.list_run_approvals round out the resource. The SSE progress stream
(GET /api/agents/{id}/runs/{runId}/stream) is not generated — consume it
with the CLI or raw HTTP. See Agent runs.
Approvals
agents:approve and must own the
run that raised the approval — and because that makes every decision a
self-approval, the credential’s bound user must also hold the
ai.approve_actions RBAC permission. Without it you get 403
SELF_APPROVAL_FORBIDDEN.
Everything else
Client-level calls
whoami() returns the identity the presented credential authenticates as — the
fastest way to confirm a key is live and bound to the user you expect.
No
api_keys resource is generated. /api/api-keys* rejects every
API-key-authenticated request with 403 FORBIDDEN (“API keys cannot be managed
with an API key — sign in to the dashboard”) before the handler runs, so the
methods would be guaranteed-dead code. Mint and rotate keys in the dashboard
under Settings → API Keys.No mcp resource either. MCP is spoken over JSON-RPC by MCP clients, and
the SDK is pinned to https://api.nexspace365.com, where every /mcp path
answers 403 MCP_HOST_NOT_ALLOWED. Point an MCP client at
https://mcp.nexspace365.com instead.Typed models
Responses are typed models generated from the OpenAPI schemas, so attribute access and IDE autocomplete work:stainless.config.yml — Facility,
Staff, Shift, Credential, WebhookSubscription, WebhookEvent,
DashboardStats, ApprovalResolution.
Pinning an API version
SendNexSpace-Version as a per-request header. Omit it and you get the latest
version.
2026-07-24 is the current latest. Discover the catalog with
client.api_versions(), and see Versioning.
Error Handling
The generated client raises an exception hierarchy rooted atAPIStatusError,
one class per HTTP status family:
e.body is:
requestId when you email admin@nexspace365.com. See Errors for the
full code list.
Idempotency
Mutations are not given an automatic key. Pass one yourself with theidempotency_key= request option, which sends the Idempotency-Key header:
409 Conflict. See
Idempotency.
Async Support
Every resource and method above has an async twin onAsyncNexSpace
(default_client_name is pinned to NexSpace in stainless.config.yml, so
the async class is named AsyncNexSpace, not AsyncNexspace):
base_url, max_retries=2,
timeout=60.0) and raises the same APIStatusError hierarchy.
