Skip to main content

Usage-based billing SDK for AI applications

Project description

Stoa SDK

Usage-based billing SDK for AI applications. Wrap your AI provider calls to automatically meter usage and bill your users.

Installation

pip install onstoa

Quick Start

from fastapi.responses import RedirectResponse

from stoa import Stoa, StoaChargeRequiredError

# Reads STOA_API_KEY from environment
stoa = Stoa()

# Use your app's user ID for billing calls
client = stoa.openai(user_id="user_123")

try:
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": "Hello!"}]
    )
except StoaChargeRequiredError:
    payment = stoa.create_payment_session(
        user_id="user_123",
        email="ada@example.com",
        return_url="https://app.example.com/billing/stoa-return",
    )
    if not payment.checkout_url:
        raise RuntimeError("Stoa did not return a checkout URL")
    raise RedirectResponse(payment.checkout_url, status_code=303)

Typical flow:

  1. call stoa.create_payment_session(...) when you want to start a payment flow
  2. keep using your app user_id in SDK billing calls
  3. if a metered call raises StoaChargeRequiredError, call stoa.create_payment_session(...)

For existing users who predate your Stoa integration, call stoa.create_payment_session(...) before their first billable AI request. The operation is idempotent.

Onboard Users

Stoa can stay invisible to the customer while still owning the canonical user and membership records.

Explicitly bootstrap a member

register_member(...) is still available if you want to bootstrap a user eagerly during signup.

from stoa import Stoa

stoa = Stoa(api_key=STOA_API_KEY, base_url=STOA_BASE_URL)

result = stoa.register_member(
    registration_secret=STOA_REGISTRATION_SECRET,
    user_id=user.id,
    email=user.email,
    name=user.name,
    avatar_url=user.avatar_url,
)

# Optional: store the membership ID for debugging or richer account UX.
persist_membership_binding(
    user_id=user.id,
    membership_id=result.membership_id,
)

Stoa registers the user for billing in your app. Your app can continue billing that user with their user_id.

Start a payment flow

If you want an explicit pay or add-funds action in your product:

payment = stoa.create_payment_session(
    user_id=user.id,
    email=user.email,
    return_url="https://app.example.com/billing/stoa-return",
)

Send the user to payment.checkout_url. The response also carries the payment ID.

Recover from StoaChargeRequiredError

If a metered call fails because the user is not yet chargeable in Stoa, start a payment flow explicitly with create_payment_session(...):

from fastapi.responses import RedirectResponse

from stoa import StoaChargeRequiredError

client = stoa.openai(user_id=user.id)

try:
    response = client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": "Hello!"}]
    )
except StoaChargeRequiredError:
    payment = stoa.create_payment_session(
        user_id=user.id,
        email=user.email,
        return_url="https://app.example.com/billing/stoa-return",
    )
    if not payment.checkout_url:
        raise RuntimeError("Stoa did not return a checkout URL")
    raise RedirectResponse(payment.checkout_url, status_code=303)

Supported Providers

OpenAI

client = stoa.openai(user_id="user_123")

# Chat completions
response = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Explain quantum computing"}]
)

# Embeddings
embeddings = client.embeddings.create(
    model="text-embedding-3-small",
    input="Hello world"
)

Anthropic

client = stoa.anthropic(user_id="user_123")

response = client.messages.create(
    model="claude-3-5-sonnet-20241022",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Write a haiku about Python"}]
)

Claude Agent SDK

from claude_agent_sdk import query

stream = stoa.wrap_claude_agent_query(
    query(prompt="Write a haiku about Python"),
    user_id="user_123",
)

async for message in stream:
    handle_agent_message(message)

You can also wrap a ClaudeSDKClient instance:

from claude_agent_sdk import ClaudeSDKClient

client = stoa.wrap_claude_agent_client(
    ClaudeSDKClient(),
    user_id="user_123",
)

async for message in client.receive_response():
    handle_agent_message(message)

Stoa yields the original Claude Agent SDK messages unchanged and emits anthropic.messages usage after the stream finishes. Billing uses Stoa's Anthropic rate card from token quantities, not Claude's estimated total_cost_usd. Cache writes default to the Anthropic 5 minute cache tier until Claude Agent SDK exposes a reliable cache TTL split.

OpenRouter

Access 100+ models through a single API:

client = stoa.openrouter(user_id="user_123")

# Use any model available on OpenRouter
response = client.chat.completions.create(
    model="meta-llama/llama-3.1-70b-instruct",
    messages=[{"role": "user", "content": "Hello!"}]
)

ElevenLabs

client = stoa.elevenlabs(user_id="user_123")

audio = client.text_to_speech.convert(
    voice_id="JBFqnCBsd6RMkjVDRZzb",
    text="Hello, welcome to our application!"
)

Environment Variables

Variable Required Default Description
STOA_API_KEY Yes - Your Stoa application API key
STOA_REGISTRATION_SECRET No - Registration signing secret for onboarding users from your app

Example .env file

# Required
STOA_API_KEY=stoa_app_xxx
STOA_REGISTRATION_SECRET=stoa_reg_xxx

# Optional - override API endpoint
STOA_BASE_URL=https://www.onstoa.com/api

Documentation

See docs.onstoa.com for full documentation.

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

onstoa-0.2.10.tar.gz (152.2 kB view details)

Uploaded Source

Built Distribution

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

onstoa-0.2.10-py3-none-any.whl (30.4 kB view details)

Uploaded Python 3

File details

Details for the file onstoa-0.2.10.tar.gz.

File metadata

  • Download URL: onstoa-0.2.10.tar.gz
  • Upload date:
  • Size: 152.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for onstoa-0.2.10.tar.gz
Algorithm Hash digest
SHA256 9957f8bb1848817130fd16b33ffc375ea94eec3c6527d992a3b62d63e6ca16bb
MD5 0f7da4fa7cd80d20449c6eaea30cf1b9
BLAKE2b-256 c121abd53746ef8c10214c712ef85d2bd7a718ac5ab301d5b6f4d4c9211bba8d

See more details on using hashes here.

Provenance

The following attestation bundles were made for onstoa-0.2.10.tar.gz:

Publisher: publish-sdk-python.yml on stoa-org/stoa

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file onstoa-0.2.10-py3-none-any.whl.

File metadata

  • Download URL: onstoa-0.2.10-py3-none-any.whl
  • Upload date:
  • Size: 30.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for onstoa-0.2.10-py3-none-any.whl
Algorithm Hash digest
SHA256 4174434bf6e4a2439ab7f9272905efcd1c5a04a3542fac4534cf16e156fccd82
MD5 0d809c67cce8662feb45e5a5abf16745
BLAKE2b-256 b87121c75d5d62ca5212f9109721f11b5893c5396c20ea187ed86ad5dbb49abb

See more details on using hashes here.

Provenance

The following attestation bundles were made for onstoa-0.2.10-py3-none-any.whl:

Publisher: publish-sdk-python.yml on stoa-org/stoa

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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