Official Python SDK for the OpenSettle API. Stablecoin billing on Base, Ethereum, Polygon, Arbitrum, Solana, and Tron.
Reason this release was yanked:
Response envelope unwrap bug — result.id was always None on create/retrieve/update. Upgrade to opensettle>=0.3.0.
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
from opensettle import OpenSettle
os = OpenSettle(
api_key="sk_test_…", # or os.environ["OPENSETTLE_KEY"]
workspace_id="ws_…", # or os.environ["OPENSETTLE_WORKSPACE"]
)
# 1. Create a customer.
customer = os.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 = os.products.create(name="Pro plan")
price = os.products.create_price(
product["id"],
amount=19_900, # minor units
currency="USD",
interval="month",
)
# 3. Start a hosted-checkout subscription.
checkout = os.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
Async
import asyncio
from opensettle import AsyncOpenSettle
async def main() -> None:
async with AsyncOpenSettle(api_key="sk_test_…", workspace_id="ws_…") as os:
customer = await os.customers.create(email="ada@example.com")
print(customer["id"])
asyncio.run(main())
Webhooks
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
from opensettle import OpenSettle, RateLimitError, SettlementError
try:
os.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.2.0.tar.gz.
File metadata
- Download URL: opensettle-0.2.0.tar.gz
- Upload date:
- Size: 40.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 |
338a9e50c90f8fcf64f2654a42b9b1b18502a480ad1b928e08dcbf71d1141579
|
|
| MD5 |
b0c5ae60b8fc2981afb4a58a89776ed5
|
|
| BLAKE2b-256 |
cc275bd8f128750bdb7315713f3306bbf98d5f16e7bfd17ad62731b5beb15c84
|
Provenance
The following attestation bundles were made for opensettle-0.2.0.tar.gz:
Publisher:
publish.yml on OpenSettle/opensettle-sdk-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
opensettle-0.2.0.tar.gz -
Subject digest:
338a9e50c90f8fcf64f2654a42b9b1b18502a480ad1b928e08dcbf71d1141579 - Sigstore transparency entry: 1518603899
- Sigstore integration time:
-
Permalink:
OpenSettle/opensettle-sdk-python@6f2596e33f74750039d792c21745d56835dc9f9c -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/OpenSettle
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6f2596e33f74750039d792c21745d56835dc9f9c -
Trigger Event:
push
-
Statement type:
File details
Details for the file opensettle-0.2.0-py3-none-any.whl.
File metadata
- Download URL: opensettle-0.2.0-py3-none-any.whl
- Upload date:
- Size: 29.1 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 |
583308f9e8195b82d3c83bde6a25c48d7b97d845650630b21c1ed888d5cc10c4
|
|
| MD5 |
adf03f55d30bf4b4f28f1dc962af4e74
|
|
| BLAKE2b-256 |
5d77d21bbf2b7f6206002ce897ed926790c7454b4fd1908411e8a3946c4027d3
|
Provenance
The following attestation bundles were made for opensettle-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on OpenSettle/opensettle-sdk-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
opensettle-0.2.0-py3-none-any.whl -
Subject digest:
583308f9e8195b82d3c83bde6a25c48d7b97d845650630b21c1ed888d5cc10c4 - Sigstore transparency entry: 1518603907
- Sigstore integration time:
-
Permalink:
OpenSettle/opensettle-sdk-python@6f2596e33f74750039d792c21745d56835dc9f9c -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/OpenSettle
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6f2596e33f74750039d792c21745d56835dc9f9c -
Trigger Event:
push
-
Statement type: