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:spapslatest_version:0.4.1minimum_runtime:Python >=3.9api_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
- Keep the high-level client familiar to teams already using the TypeScript SDK.
- Return typed models instead of raw dicts wherever the response shape is stable.
- Preserve escape hatches for custom token storage, HTTP transport, retries, and logging.
- 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
ghand 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
10f9004886c7ae6505cbb1664b3bf7e6f2256c08f93b04342ffb3d535ebf3f2a
|
|
| MD5 |
4e67776e5bb2da13a1a2d5f18d78b295
|
|
| BLAKE2b-256 |
e73f2991fe53fb3a0f5ec2a3a6cec4265a30d7d423e3e18dfada83d8259b883f
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5a72ad3ca075c4350b26664441ad2b77402ad0c4fafdb44984b31e3faefefb12
|
|
| MD5 |
5a3827d539a10c5ea73f86733ad58d7c
|
|
| BLAKE2b-256 |
4b1378cec5da05d0b9f62cf9cad48e12dc8dc46caf5f412e3b5c5188e3482d9a
|