Skip to Content
SPAPS is proprietary hosted SaaS. Paid access required; pre-1.0 contracts may change. Terms and access
PackagesPython Client

SPAPS Python Client

The Python client distribution name is spaps, and the import path is spaps_client.

Verified public release: spaps 0.8.2, with Python 3.9 or newer. The API below was checked against that release wheel. The upstream 0.8.3.dev0 checkout is development source, not a published release.

Install vs Import

pip install spaps==0.8.2 python -c "from importlib.metadata import version; print(version('spaps'))"
from spaps_client import SpapsClient, AsyncSpapsClient

Install name and import name are intentionally different: spaps (package) and spaps_client (module).

Sync And Async Aggregate Clients

Both aggregate clients expose a grouped API surface and shared token helpers (set_tokens, get_tokens, clear_tokens):

ClientMain grouped helpers
SpapsClientauth, sessions, payments, usage, whitelist, secure_messages, issue_reporting, metrics, support_telemetry
AsyncSpapsClientauth, sessions, payments, usage, whitelist, secure_messages, issue_reporting, metrics, entitlements, dayrate, users

Sync Example

import os from spaps_client import MfaRequiredChallenge, SpapsClient client = SpapsClient( base_url="https://api.sweetpotato.dev", # Load a provisioned staging secret from server-side secret storage. api_key=os.environ["SPAPS_API_KEY"], ) try: auth_result = client.auth.sign_in_with_password( email="user@example.com", password="correct-horse-battery-staple", ) if isinstance(auth_result, MfaRequiredChallenge): raise RuntimeError(f"Complete MFA challenge {auth_result.challenge_id} before API calls") if auth_result.user is None: raise RuntimeError("Sign-in returned tokens without a user projection") session = client.sessions.get_current_session() print(auth_result.user.email, session.session_id) finally: client.close()

Async Example

import asyncio import os from spaps_client import AsyncSpapsClient, MfaRequiredChallenge async def main() -> None: client = AsyncSpapsClient( base_url="https://api.sweetpotato.dev", api_key=os.environ["SPAPS_API_KEY"], ) try: auth_result = await client.auth.sign_in_with_password( email="user@example.com", password="correct-horse-battery-staple", ) if isinstance(auth_result, MfaRequiredChallenge): raise RuntimeError( f"Complete MFA challenge {auth_result.challenge_id} before API calls" ) items = await client.issue_reporting.list_issue_reports(limit=10) print(items.total) finally: await client.aclose() asyncio.run(main())

Helper Clients And Utilities

The package also exports narrower helpers when you do not want the aggregate clients:

HelperPurpose
EntitlementsClient, AsyncEntitlementsClientEntitlement list/check/claim/history and admin grant/revoke flows
IssueReportingClient, AsyncIssueReportingClientIssue status/history/create/update/reply and voice-token support
EmailClient, AsyncEmailClientTemplate list/preview/send
UsersClient, AsyncUsersClientBatch email and user lookup helpers
DeviceFlowClientOAuth device flow (/api/cli/device/authorize, /api/cli/device/token)
PermissionChecker and related helpersRole/admin permission checks
verify_spaps_webhookSPAPS webhook signature verification
verify_crypto_webhook_signatureCrypto webhook signature verification

Retry, Logging, And Token Storage

spaps_client.http exposes RetryConfig, LoggingHooks, and default_logging_hooks. Token persistence is available via TokenStorage implementations:

  • InMemoryTokenStorage
  • FileTokenStorage (defaults to ~/.config/spaps/tokens.json)
from spaps_client import ( FileTokenStorage, RetryConfig, SpapsClient, default_logging_hooks, ) client = SpapsClient( base_url="https://api.example.test", api_key="spaps_sec_example", retry_config=RetryConfig(max_attempts=4, backoff_factor=0.2), logging_hooks=default_logging_hooks(), token_storage=FileTokenStorage(), )

Device Flow

DeviceFlowClient implements RFC 8628-style device authorization for CLI/headless flows. It uses the provisioned application slug as client_id; these public-client requests do not send an application API key.

from spaps_client import DeviceFlowClient flow = DeviceFlowClient( base_url="https://api.example.test", client_id="application-slug", ) # start() -> returns user_code + verification_uri # poll() -> waits for token issuance

Webhook Verification

from spaps_client import verify_spaps_webhook payload = verify_spaps_webhook( body=request_body_bytes, signature=request_headers["X-SPAPS-Signature"], secret="whsec_example", ) print(payload.type)

Issue Reporting Surface

IssueReportingClient and AsyncIssueReportingClient expose:

  • get_issue_report_status
  • list_issue_reports
  • get_issue_report
  • create_issue_report
  • update_issue_report
  • reply_to_issue_report
  • create_voice_token

Use create_voice_token for browser voice-input integrations so the browser gets a short-lived token from SPAPS instead of a long-lived provider secret.

Entitlements Surface

EntitlementsClient and AsyncEntitlementsClient expose:

  • get_user_entitlements
  • check_access
  • claim_pending
  • get_purchase_history
  • get_changes
  • grant_manual and revoke (admin flows)

These helper clients are useful when you want entitlement logic outside the aggregate client surface.

Validation

Record the installed version with importlib.metadata.version('spaps') and retain your dependency lock. Typecheck your application’s calls, then verify sign-in, session refresh, and an entitlement decision against the provisioned staging application.

Pair this page with Issue reporting and support and Billing and entitlements for backend contract details.