Skip to main content

Sweet Potato Authentication & Payment Service Python client

Project description

Sweet Potato Python Client

Python SDK for the Sweet Potato Authentication & Payment Service (SPAPS). It packages the common auth, session, payment, secure messaging, issue reporting, webhook, and operational client flows used by SPAPS-backed apps and services.

pip install spaps

TL;DR

The Problem: calling SPAPS directly from Python usually means reimplementing token storage, retry behavior, error parsing, and endpoint wrappers across every service.

The Solution: the spaps Python distribution gives you sync and async clients, typed response models, retry/logging hooks, and standalone helpers for the parts of the SPAPS API that need narrower integration points.

Why Use the Python Client?

Feature What it gives you
Sync + async ergonomics SpapsClient and AsyncSpapsClient cover the common auth and session workflows
Typed payloads Pydantic models for auth, sessions, payments, entitlements, webhooks, and more
Retry and logging hooks Configurable HTTP retries plus request/response logging helpers
Standalone helpers Device flow, webhooks, permission checks, issue reporting, support telemetry, and specialty clients

Metadata

  • package_name: spaps
  • latest_version: 0.4.1
  • minimum_runtime: Python >=3.9
  • api_base_url: https://api.sweetpotato.dev

Quick Example

from spaps_client import SpapsClient

client = SpapsClient(
    base_url="http://localhost:3301",
    api_key="test_key_local_dev_only",
)

tokens = client.auth.sign_in_with_password(
    email="user@example.com",
    password="Secret123!",
)
print(tokens.user.email)

current = client.sessions.get_current_session()
print(current.session_id)

products = client.payments.list_products(category="subscription", active=True, limit=5)
print(products.total)

client.close()

Async Example

import asyncio

from spaps_client import AsyncSpapsClient


async def main() -> None:
    client = AsyncSpapsClient(
        base_url="http://localhost:3301",
        api_key="test_key_local_dev_only",
    )
    try:
        await client.auth.sign_in_with_password(
            email="user@example.com",
            password="Secret123!",
        )
        sessions = await client.sessions.list_sessions()
        print(sessions.total)
    finally:
        await client.aclose()


asyncio.run(main())

Design Principles

  1. Keep the high-level client familiar to teams already using the TypeScript SDK.
  2. Return typed models instead of raw dicts wherever the response shape is stable.
  3. Preserve escape hatches for custom token storage, HTTP transport, retries, and logging.
  4. Keep specialty integrations available as standalone helpers instead of forcing everything through one client.

API Surface

High-Level Clients

Client Best for
SpapsClient Sync auth, sessions, payments, usage, whitelist, secure messages, issue reporting, metrics, and support telemetry
AsyncSpapsClient Async auth, sessions, payments, usage, whitelist, secure messages, issue reporting, metrics, entitlements, dayrate, and users

Standalone Helpers

Helper Purpose
EntitlementsClient / AsyncEntitlementsClient Resource entitlements, purchase history, manual grants/revokes
EmailClient / AsyncEmailClient Template listing, preview, and send flows
UsersClient / AsyncUsersClient Batch user and email lookups
DeviceFlowClient Device-code login workflows
PermissionChecker Client-side role and admin convenience checks
verify_spaps_webhook Signature verification for incoming SPAPS webhooks

Configuration

Constructor values override package defaults.

from spaps_client import SpapsClient, RetryConfig, default_logging_hooks

client = SpapsClient(
    base_url="https://api.sweetpotato.dev",
    api_key="spaps_sec_example",
    retry_config=RetryConfig(max_attempts=4, backoff_factor=0.2),
    logging_hooks=default_logging_hooks(),
)

Common parameters:

Parameter Purpose
base_url Target SPAPS API origin
api_key Application or service API key
request_timeout Per-request timeout
token_storage Custom token persistence backend
http_client Injected httpx.Client or httpx.AsyncClient
retry_config Retry/backoff policy
logging_hooks Structured request/response logging callbacks

Common Flows

Magic Links and Password Reset

from spaps_client import SpapsClient

client = SpapsClient(base_url="http://localhost:3301", api_key="test_key_local_dev_only")

client.auth.send_magic_link(email="user@example.com")
client.auth.request_password_reset(email="user@example.com")
client.auth.confirm_password_reset(
    token="reset-token-from-email",
    new_password="Sup3rStrong!",
)

client.close()

Permission Checks

from spaps_client import PermissionChecker

checker = PermissionChecker(customAdmins=["founder@example.com"])
role = checker.getRole("user@example.com")

if checker.requiresAdmin({"email": "user@example.com"}):
    raise PermissionError(
        checker.getErrorMessage("admin", role, action="change billing settings")
    )

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)

Architecture

Your Python app
  |
  +--> SpapsClient / AsyncSpapsClient
  |       |
  |       +--> auth / sessions / payments / usage / secure messages
  |       +--> issue reporting / metrics / support telemetry
  |
  +--> standalone helpers
          |
          +--> entitlements / users / email / device flow / webhooks
                  |
                  v
               SPAPS HTTP API

Validation and Development

From the repository root:

npm run lint:python-client
npm run typecheck:python-client
npm run test:python-client

For local package setup:

cd packages/python-client
pip install -e '.[dev]'

Troubleshooting

ValueError: Access token not found

Authenticate first with client.auth... helpers, or pre-seed tokens with set_tokens(...).

401 or 403 responses

Confirm the API key, token scope, and endpoint role requirements all match the target environment.

Hosted examples fail against localhost

Set base_url="http://localhost:3301" and use a local-development key or the relevant test credentials.

I need more control over HTTP behavior

Inject a custom httpx client or pass RetryConfig and logging hooks.

Which client should I start with?

Use SpapsClient unless your app is already async end-to-end.

Limitations

  • Not every SPAPS helper is available on both the sync and async top-level clients.
  • Brand-new backend endpoints may require a client release before typed wrappers exist here.
  • Client-side permission helpers improve ergonomics but do not replace server-side authorization.

FAQ

Is this package only for backend services?

No. It is suitable for any Python consumer of the SPAPS API.

Does it persist tokens automatically?

Yes, through the configured token storage backend. You can swap the storage implementation if needed.

Can I use it without the high-level client?

Yes. The package exports narrower clients and helpers for more specialized integrations.

Is there webhook support?

Yes. Use verify_spaps_webhook for SPAPS signature verification.

Does it support async codebases?

Yes. Use AsyncSpapsClient and the async helper clients.

About Contributions

About Contributions: Please don't take this the wrong way, but I do not accept outside contributions for any of my projects. I simply don't have the mental bandwidth to review anything, and it's my name on the thing, so I'm responsible for any problems it causes; thus, the risk-reward is highly asymmetric from my perspective. I'd also have to worry about other "stakeholders," which seems unwise for tools I mostly make for myself for free. Feel free to submit issues, and even PRs if you want to illustrate a proposed fix, but know I won't merge them directly. Instead, I'll have Claude or Codex review submissions via gh and independently decide whether and how to address them. Bug reports in particular are welcome. Sorry if this offends, but I want to avoid wasted time and hurt feelings. I understand this isn't in sync with the prevailing open-source ethos that seeks community contributions, but it's the only way I can move at this velocity and keep my sanity.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

spaps-0.5.0.tar.gz (84.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

spaps-0.5.0-py3-none-any.whl (81.2 kB view details)

Uploaded Python 3

File details

Details for the file spaps-0.5.0.tar.gz.

File metadata

  • Download URL: spaps-0.5.0.tar.gz
  • Upload date:
  • Size: 84.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for spaps-0.5.0.tar.gz
Algorithm Hash digest
SHA256 10f9004886c7ae6505cbb1664b3bf7e6f2256c08f93b04342ffb3d535ebf3f2a
MD5 4e67776e5bb2da13a1a2d5f18d78b295
BLAKE2b-256 e73f2991fe53fb3a0f5ec2a3a6cec4265a30d7d423e3e18dfada83d8259b883f

See more details on using hashes here.

File details

Details for the file spaps-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: spaps-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 81.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for spaps-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5a72ad3ca075c4350b26664441ad2b77402ad0c4fafdb44984b31e3faefefb12
MD5 5a3827d539a10c5ea73f86733ad58d7c
BLAKE2b-256 4b1378cec5da05d0b9f62cf9cad48e12dc8dc46caf5f412e3b5c5188e3482d9a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page