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 stoa
Quick Start
from stoa import Stoa, InsufficientBalanceError
# Reads STOA_API_KEY and STOA_APP_ID from environment
stoa = Stoa()
# 1. Register or reuse the member from your backend
stoa.register_member(
connect_secret=STOA_CONNECT_SECRET,
user_id="user_123",
email="ada@example.com",
)
# 2. Use your app's own 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 InsufficientBalanceError as e:
print(f"Please top up: {e.topup_url}")
Typical flow:
- call
stoa.register_member(...)from your backend - keep using your own app
user_idin SDK billing calls - send the user to
e.topup_urlif they need funds
Onboard Users
Stoa can stay invisible to the customer while still owning the canonical user and membership records.
User onboards via your app
From your backend, call the SDK once with your connect secret and the user's verified app identity:
from stoa import Stoa
stoa = Stoa(api_key=STOA_API_KEY, base_url=STOA_BASE_URL, app_id=STOA_APP_ID)
result = stoa.register_member(
connect_secret=STOA_CONNECT_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 its own user_id.
Optional: open a hosted top-up page
If you want an explicit "Add funds" action in your product:
topup_url = stoa.get_topup_url(user_id=user.id)
This returns a hosted Stoa payment page for that app user.
User installs via Stoa marketplace
Marketplace installs use the install flow below.
Install callback
Add a callback endpoint that verifies the Stoa install token and activates the membership for your app user. Both flows should converge on the same stored membership binding in your app.
from stoa import Stoa
stoa = Stoa()
def stoa_callback(token: str):
claims = stoa.verify_install_callback(token=token)
user = find_or_create_user(
email=claims["email"],
name=claims["name"],
)
install = stoa.exchange_install_token(
token=token,
user_id=user.id,
)
persist_membership_binding(
user_id=user.id,
membership_id=install.membership_id,
)
return create_session_and_redirect(user)
The SDK fetches Stoa's public key for you and keeps the server-side activation step in place, so the secure flow does not become app boilerplate.
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"}]
)
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_APP_ID |
No | - | Your Stoa application ID (required for member registration unless passed explicitly) |
STOA_BASE_URL |
No | https://api.onstoa.com |
Stoa API base URL (for self-hosted or testing) |
Example .env file
# Required
STOA_API_KEY=stoa_app_xxx
STOA_APP_ID=app_xxx
# Optional - override API endpoint
STOA_BASE_URL=https://api.onstoa.com
# Provider keys (only needed for providers you use)
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
OPENROUTER_API_KEY=sk-or-...
ELEVENLABS_API_KEY=...
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
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 onstoa-0.2.0.tar.gz.
File metadata
- Download URL: onstoa-0.2.0.tar.gz
- Upload date:
- Size: 120.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f39d6de0924d5adc8f88922157f958be0e6ba9947a083bd6f0c6f19f8180d6da
|
|
| MD5 |
7ac0f68d2f25f59614dcf48d88e21c3a
|
|
| BLAKE2b-256 |
2fc67c6cc3e5e8c90fd0c88e1d44fb4525b223a71c605e21fe7a4857eeaebe23
|
Provenance
The following attestation bundles were made for onstoa-0.2.0.tar.gz:
Publisher:
publish-sdk-python.yml on stoa-org/stoa
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
onstoa-0.2.0.tar.gz -
Subject digest:
f39d6de0924d5adc8f88922157f958be0e6ba9947a083bd6f0c6f19f8180d6da - Sigstore transparency entry: 1280223488
- Sigstore integration time:
-
Permalink:
stoa-org/stoa@22b0c476cec6968bda7dc8194d6e6664ae3d85b2 -
Branch / Tag:
refs/tags/sdk-py-v0.2.0 - Owner: https://github.com/stoa-org
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-sdk-python.yml@22b0c476cec6968bda7dc8194d6e6664ae3d85b2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file onstoa-0.2.0-py3-none-any.whl.
File metadata
- Download URL: onstoa-0.2.0-py3-none-any.whl
- Upload date:
- Size: 26.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1c667e9b6317c5294df3333f7d583b56a4e909e578d5f78cd850697bbf14ee0a
|
|
| MD5 |
01efd56655d97d0f0db3fd797ca71c47
|
|
| BLAKE2b-256 |
f5ec6d50d8de851969b8cebf45c555dd9a7020c0394e668926d02a0f5fc2e274
|
Provenance
The following attestation bundles were made for onstoa-0.2.0-py3-none-any.whl:
Publisher:
publish-sdk-python.yml on stoa-org/stoa
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
onstoa-0.2.0-py3-none-any.whl -
Subject digest:
1c667e9b6317c5294df3333f7d583b56a4e909e578d5f78cd850697bbf14ee0a - Sigstore transparency entry: 1280223489
- Sigstore integration time:
-
Permalink:
stoa-org/stoa@22b0c476cec6968bda7dc8194d6e6664ae3d85b2 -
Branch / Tag:
refs/tags/sdk-py-v0.2.0 - Owner: https://github.com/stoa-org
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-sdk-python.yml@22b0c476cec6968bda7dc8194d6e6664ae3d85b2 -
Trigger Event:
push
-
Statement type: