Official Python SDK for the OpenSettle API. Stablecoin billing on Base, Ethereum, Polygon, Arbitrum, Solana, and Tron.
Project description
opensettle
Official Python SDK for the OpenSettle API.
Non-custodial stablecoin billing on Base, Ethereum, Polygon, Arbitrum, Solana and Tron. Typed end-to-end, sync and async, signed-webhook verifier included, idempotent writes by default.
Install
pip install opensettle
Requires Python 3.9+.
Conventions
- Method names are snake_case (Python idiom):
os.customers.create(...). - Body fields and response keys are camelCase, matching the API's wire
format exactly. Pass
customerEmail=...notcustomer_email=.... Readresult["createdAt"]notresult["created_at"]. Zero translation, no surprises.
Quickstart
import os
from opensettle import OpenSettle
client = OpenSettle(
api_key=os.environ["OPENSETTLE_KEY"],
workspace_id=os.environ["OPENSETTLE_WORKSPACE"],
)
# 1. Create a customer.
customer = client.customers.create(
email="ada@example.com",
name="Ada Lovelace",
country="GB",
)
print(customer["id"]) # cus_…
print(customer["createdAt"]) # ISO-8601
# 2. Create a product + price.
product = client.products.create(name="Pro plan")
price = client.products.create_price(
product["id"],
amount=19_900, # minor units
currency="USD",
interval="month",
)
# 3. Start a hosted-checkout subscription.
checkout = client.checkouts.create(
mode="subscription",
customerId=customer["id"],
priceId=price["id"],
chain="base",
token="USDC",
successUrl="https://merchant.com/ok",
cancelUrl="https://merchant.com/cancel",
)
print(checkout["hostedUrl"]) # link to send the customer
Hosted checkout is EVM-only
The API accepts chain="solana" and chain="tron" on a checkout, and the
chain reader will detect inbound SPL / TRC-20 deposits to verified wallets.
However, the customer-facing hosted checkout page is currently EVM-only —
Base, Ethereum, Polygon, and Arbitrum. Until Solana and Tron land in the
hosted UI, drive those flows directly against /wallets + the chain reader
rather than checkouts.create.
Async
import asyncio
from opensettle import AsyncOpenSettle
async def main() -> None:
async with AsyncOpenSettle(api_key="sk_test_…", workspace_id="ws_…") as client:
customer = await client.customers.create(email="ada@example.com")
print(customer["id"])
asyncio.run(main())
Webhooks
import os
from opensettle import verify_webhook, WebhookVerificationError
@app.post("/webhooks/opensettle")
async def handler(request):
raw = await request.body()
try:
event = verify_webhook(
raw_body=raw,
signature_header=request.headers.get("x-opensettle-signature"),
secret=os.environ["WHSEC"],
)
except WebhookVerificationError as e:
return Response(status=400, content=f"bad signature: {e.reason}")
# event.data is the decoded JSON; event.timestamp is the signed epoch
return Response(status=200)
Error handling
import time
from opensettle import RateLimitError, SettlementError
try:
client.payments.refund("pay_…", amountMinor=500)
except RateLimitError as e:
time.sleep(e.retry_after or 1)
retry()
except SettlementError as e:
if e.code == "insufficient_confirmations":
wait_and_retry()
The full error hierarchy:
OpenSettleError
├── InvalidRequestError
├── InvalidStateTransitionError
├── AuthenticationError
├── ForbiddenError
├── NotFoundError
├── ConflictError
├── RateLimitError # carries `retry_after: float | None`
├── SettlementError # chain_reverted | insufficient_confirmations | signing_required
├── StepUpRequiredError # aal_required
├── APIError # internal_error or forward-compat unknown codes
└── NetworkError # transport-layer / timeout
Every error carries code, status, request_id, and param so you
can quote the request ID in support tickets.
Configuration
os = OpenSettle(
api_key="sk_test_…",
workspace_id="ws_…",
base_url="https://api.opensettle.io", # default; override for self-host
test_mode=None, # None | True | False env-assertion gate
timeout=30.0, # seconds; default 30s
max_network_retries=3, # 0 to disable retries
)
test_mode=True refuses sk_live_… keys; test_mode=False refuses
sk_test_…. Leave None to accept either and let the API decide.
Resources
| Resource | Methods |
|---|---|
customers |
list, retrieve, create, update, delete |
products |
list, retrieve, create, update, list_prices, create_price, update_price, delete, delete_price |
invoices |
list, retrieve, create, send, remind, void |
payments |
list, retrieve, refund, refund_broadcast |
subscriptions |
list, retrieve, create, pause, resume, cancel, change_plan |
checkouts |
create, retrieve |
webhook_endpoints |
list, retrieve, create, update, delete, rotate_secret, test |
License
MIT — see LICENSE.
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 opensettle-0.5.1.tar.gz.
File metadata
- Download URL: opensettle-0.5.1.tar.gz
- Upload date:
- Size: 47.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ec12883374f31f9af33f4f0152fccbcd2d4ed30338ff01d21af4c84c9a6720d
|
|
| MD5 |
c3a4e2b8142b8da88b704d9ce76a31ef
|
|
| BLAKE2b-256 |
33b46f13b12f8e860f67674fff0d648fb5fbd586e8051d9c515949b5a098194b
|
File details
Details for the file opensettle-0.5.1-py3-none-any.whl.
File metadata
- Download URL: opensettle-0.5.1-py3-none-any.whl
- Upload date:
- Size: 33.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d93309b3b641f7667f3110faf2926940a5f0090d43db10e9ded8d73c21fff585
|
|
| MD5 |
3f5bd07987a24caf8a3da86bae018a79
|
|
| BLAKE2b-256 |
cd2a53bfc3c93ae8be750a6ab1ac70d6a3c87e67b135c3bd70bffea752a7d942
|