Skip to main content

PPUSSH Ecosystem SDK — Accounts (OIDC) + Payments client for Python

Project description

ppussh

Official Python SDK for the PPUSSH platform — Accounts (OIDC / OAuth 2.0) and Payments in a single, async-first client.

Requirements

  • Python 3.12+
  • An Accounts client_id and client_secret (obtain from the Accounts admin console)
  • A running instance of the Accounts and Payments services

Installation

pip install ppussh

Configuration

The SDK requires the base URLs for both services. Set them via environment variables (recommended for production) or pass them directly to the constructor.

Environment variable Purpose
PPUSSH_ACCOUNTS_URL Base URL of the Accounts API
PPUSSH_PAYMENTS_URL Base URL of the Payments API
export PPUSSH_ACCOUNTS_URL="https://accounts.example.com"
export PPUSSH_PAYMENTS_URL="https://payments.example.com"

Quick start

from ppussh import PpusshClient

# URLs are read from PPUSSH_ACCOUNTS_URL / PPUSSH_PAYMENTS_URL env vars,
# or pass them explicitly:
client = PpusshClient(
    client_id="your-product-client-id",
    client_secret="your-product-client-secret",
    payments_admin_key="your-payments-admin-key",  # optional; needed for admin calls
    # accounts_url="https://accounts.example.com",  # or set PPUSSH_ACCOUNTS_URL
    # payments_url="https://payments.example.com",  # or set PPUSSH_PAYMENTS_URL
)

OIDC callback (FastAPI example)

from fastapi import FastAPI, Query
from ppussh import PpusshClient

app = FastAPI()
client = PpusshClient(client_id="...", client_secret="...")

REDIRECT_URI = "https://yourapp.example.com/auth/callback"

@app.get("/auth/callback")
async def callback(code: str = Query(...)):
    token = await client.accounts.exchange_code(code, redirect_uri=REDIRECT_URI)
    # token.user contains the authenticated user's profile
    return {"user_id": token.user.id, "email": token.user.email}

Token verification middleware

from fastapi import Request, HTTPException
from ppussh import PpusshClient, PpusshAuthError

client = PpusshClient(client_id="...", client_secret="...")

async def require_auth(request: Request) -> str:
    auth_header = request.headers.get("Authorization", "")
    if not auth_header.startswith("Bearer "):
        raise HTTPException(status_code=401)
    bearer = auth_header.removeprefix("Bearer ")
    try:
        result = await client.accounts.verify_token(bearer)
    except PpusshAuthError:
        raise HTTPException(status_code=401)
    return result.user_id

Token refresh

# Uses the refresh token stored internally after exchange_code()
new_token = await client.accounts.refresh()

# Or pass an explicit refresh token:
new_token = await client.accounts.refresh(refresh_token="...")

Logout

await client.accounts.logout()  # uses stored refresh token

Billing — create a customer and subscription

from uuid import uuid4

# Create or retrieve a customer record
customer = await client.payments.create_customer(
    owner_user_id=token.user.id,
    workspace_id="ws-123",  # optional
)

# List available plans for a product
plans = await client.payments.list_plans(payment_product_id="prod-abc")

# Subscribe the customer
subscription = await client.payments.create_subscription(
    customer_id=customer.id,
    payment_product_id="prod-abc",
    plan_key="pro",
    idempotency_key=str(uuid4()),
)

Async context manager (scripts / one-off usage)

async with PpusshClient(client_id="...", client_secret="...") as client:
    token = await client.accounts.exchange_code(code, redirect_uri=REDIRECT_URI)

For long-lived services, call await client.aclose() during application shutdown to drain the connection pool.

Error handling

All exceptions are subclasses of PpusshError:

from ppussh import (
    PpusshError,          # base class
    PpusshAuthError,      # 401 — invalid or expired token / credentials
    PpusshConsentRequired,# 403 — user hasn't consented to this product's scopes
    PpusshPaymentError,   # non-2xx from the Payments service
    PpusshNetworkError,   # all retries exhausted / connection failure
)

try:
    token = await client.accounts.exchange_code(code, redirect_uri=REDIRECT_URI)
except PpusshConsentRequired as exc:
    # Redirect the user to the consent flow
    redirect_to_consent(exc.client_id, exc.product_name)
except PpusshAuthError:
    # Invalid code or expired credentials
    ...
except PpusshNetworkError:
    # Retry later
    ...

Retry policy

Condition Behaviour
5xx / network error Up to 3 attempts, exponential backoff (0.5 s, 1 s, 2 s)
429 Too Many Requests Respects Retry-After header, max 2 retries
4xx (not 429) Never retried — raises immediately

API reference

client.accounts

Method Description
exchange_code(code, *, redirect_uri) Exchange an auth code for tokens (OIDC callback)
refresh(refresh_token?) Refresh the access token
verify_token(access_token) Validate an incoming bearer token (use in middleware)
logout(refresh_token?) Revoke the session
get_user(access_token?) Fetch the authenticated user's profile
get_entitlements(access_token?) List the user's product entitlements
get_sessions(access_token?) List the user's active sessions

client.payments

Method Description
create_customer(owner_user_id, ...) Create or retrieve a customer record
get_customer(customer_id) Fetch a customer by ID
create_subscription(...) Create a subscription
list_subscriptions(customer_id, ...) List subscriptions for a customer
get_subscription(subscription_id) Fetch a subscription by ID
cancel_subscription(subscription_id, ...) Cancel a subscription
list_plans(payment_product_id) List billing plans (requires payments_admin_key)
get_product_by_accounts_id(accounts_product_id) Resolve a payments product by its Accounts ID (requires payments_admin_key)
get_mrr(...) Fetch MRR analytics (requires payments_admin_key)

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

ppussh-0.2.2.tar.gz (17.7 kB view details)

Uploaded Source

Built Distribution

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

ppussh-0.2.2-py3-none-any.whl (23.1 kB view details)

Uploaded Python 3

File details

Details for the file ppussh-0.2.2.tar.gz.

File metadata

  • Download URL: ppussh-0.2.2.tar.gz
  • Upload date:
  • Size: 17.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for ppussh-0.2.2.tar.gz
Algorithm Hash digest
SHA256 8eacd0418df90ccdd3dbbc75068c44c493fb1e185149943680291ad993c8d885
MD5 51b80b51424f5b599584499c8a8f8508
BLAKE2b-256 5ac4dda6ed935c2f86ddb9ee24e8c6bfe7ec85dc254cf029c6a76cfea226c26d

See more details on using hashes here.

File details

Details for the file ppussh-0.2.2-py3-none-any.whl.

File metadata

  • Download URL: ppussh-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 23.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for ppussh-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 3a0ee679f037b1e3eb1662fb8515aeb3aac2c15c25caf712288aa8a29bcf8fe4
MD5 8bf342ed662683422a57e69209f95c5a
BLAKE2b-256 79efd24897af24ce95675e9e405e0c74d4e2d8277f0223f267eaa15667872e2e

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