stripe-apiroute
A Python client for the Stripe API, generated with apiroute from Stripe's published OpenAPI spec and kept current by a weekly build. Methods carry the names Stripe's own SDKs use: stripe.customers.create(...), stripe.issuing.cards.list(), stripe.checkout.sessions.create(...).
- Two layers: every call works with plain dicts (
stripe.customers.retrieve("cus_123")), and.modelstakes and returns typed pydantic models (stripe.customers.models.retrieve("cus_123")). - Sync and async: add
.aioto any call for the async version. - Lazy loading: only the sections and models you use are imported. The client covers all 559 operations and about 5,000 models, and importing it takes about a tenth of a second.
- Typed: the package ships
py.typed.
Installation
pip install stripe-apiroute # or: uv add stripe-apiroute
It needs Python 3.10 or newer.
Usage
import os
from stripe_apiroute.api import StripeApi
stripe = StripeApi(api_key=os.environ["STRIPE_SECRET_KEY"])
customer = stripe.customers.create(body={"email": "jenny@example.com"}) # a dict
customer = stripe.customers.models.create( # Customer
body={
"email": "jenny@example.com",
"metadata": {"order_id": "6735"},
"address": {"city": "Paris", "line1": "1 rue de Rivoli"},
}
)
print(customer.id, customer.address.city)
recent = stripe.customers.models.list(created={"gte": 1700000000}, limit=10, expand=["data.tax"])
for customer in stripe.customers.models.list_all(limit=100): # every page, fetched as you go
print(customer.email)
session = stripe.checkout.sessions.models.create(
body={
"mode": "payment",
"success_url": "https://example.com/done",
"line_items": [{"price": "price_123", "quantity": 2}],
}
)
intent = await stripe.payment_intents.models.aio.retrieve("pi_123")
- Request bodies are sent the way Stripe expects, as form-encoded data with nested values:
metadata[order_id]=6735,line_items[][price]=price_123. Filters such ascreated={"gte": ...}go out ascreated[gte]=..., andexpand=[...]asexpand[]=.... - Sections follow Stripe's SDKs:
stripe.customers,stripe.customers.balance_transactions,stripe.payment_intents,stripe.issuing.cards,stripe.billing.meters,stripe.test_helpers.test_clocks, and so on: 75 top-level sections. - Pagination: every list operation has a
_alltwin (customers.list_all,invoices.list_all,customers.search_all…) taking the same arguments and iterating every page's items: it followshas_moreandstarting_after, ornext_pagefor searches.async forworks through.aio,.pages()gives whole pages, anditertools.isliceorbreakstops early. Which operations get one is set byspecs/stripe.pagination.yaml. - File uploads go to
files.stripe.com, as Stripe requires:stripe.files.models.create(body={"purpose": "dispute_evidence", "file": ("evidence.png", data, "image/png")}). - Errors raise
apiroute.UnexpectedResponse. Its.responsecarries Stripe's error object:error.response.json()["error"]["code"].
Keys, versions and Connect
| Argument | |
|---|---|
api_key |
A secret key (sk_live_…, sk_test_…), a restricted key (rk_…), or a function returning the current one. Sent as Authorization: Bearer …. See Stripe's API keys guide. |
stripe_account |
Acts on behalf of a connected account, through the Stripe-Account header. |
stripe_version |
Defaults to the API version of the spec this release was generated from (stripe_apiroute.spec_info.STRIPE_VERSION), which the typed models describe. Responses for another version may not match them. |
base_url |
Another host, such as stripe-mock (http://localhost:12111). Every operation then goes there, file uploads included. |
Retries and idempotency
Retries are off unless you turn them on, for example with stripe.with_options(retries=3), or retries = Retries(...) in a subclass. Once on, they follow Stripe's SDKs:
- Every
POSTcarries anIdempotency-Key: a new UUID for each call, the same on every retry of it. A payment can't be created twice. - Connection failures and timeouts are retried.
- An error response is retried when Stripe's
Stripe-Should-Retryheader says so. Without that header, a 409 (lock timeout), a 429 and server errors are retried.
For transports, timeouts and other client options, see apiroute's README.
APIs
| API | Import | Docs |
|---|---|---|
| Stripe API | from stripe_apiroute.api import StripeApi |
docs |
How this repository stays up to date
Nothing under src/stripe_apiroute/ is written by hand except auth.py and __init__.py. Everything else is generated from the spec listed in apis.yaml:
- Every Monday, the Build workflow does the following:
- Upgrades apiroute to its newest release.
- Downloads Stripe's spec into
specs/. It uses the SDK variant, whosex-stripeOperationsextensions name every operation as Stripe's SDKs do. - Writes
specs/stripe.names.json, the map of operation IDs to those names, withscripts/stripe_names.py. - Regenerates the client with
apiroute generate --operation-names. - Runs the lint and tests, then the live tests against Stripe's test mode.
- If anything changed, it commits the result to
main:feat(specs): ...when Stripe changed its spec, which produces a minor release.fix(codegen): ...when only a newer apiroute changed the generated code, which produces a patch release.
- Release then tests the commit, adds it to CHANGELOG.md, tags it, publishes the new version to PyPI and creates a GitHub release. No one has to do anything; every merge to main releases the same way.
CI checks every pull request and every release. It lints, runs the tests on Python 3.10 to 3.14, and regenerates from the committed spec to confirm the committed code matches it exactly.
Because specs/ is committed, git log -p specs/ shows exactly what Stripe changed and when.
Development
uv sync
uv run python scripts/generate.py --fetch # download the latest spec, regenerate
uv run python scripts/generate.py # regenerate from the committed spec
uv run pytest
STRIPE_TEST_SECRET_KEY=sk_test_... uv run pytest tests/live # against Stripe's test mode
uv run ruff check . && uv run ruff format --check .
The live tests create a few test-mode objects (a customer, a product and prices, a Checkout session, a small file) and clean up what Stripe lets them. They refuse to run with a key that isn't a test-mode key.
License
MIT
Metadata
Release files for stripe-apiroute 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| stripe_apiroute-0.2.0.tar.gz | 1.4 MB | Without provenance | Details for stripe_apiroute-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| stripe_apiroute-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for stripe_apiroute-0.2.0-py3-none-any.whl |
Total release size: 6.5 MB
Release files / stripe_apiroute-0.2.0.tar.gz
| Download URL | stripe_apiroute-0.2.0.tar.gz |
|---|---|
| Size | 1.4 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
061bb2c8b4167d1e0cded212b6f33fa549335b52927bc7d7afb57639696418c8
|
|
BLAKE2b-256 checksum How to use checksums |
d430937d1b27c2cc079b0aabc89ef2f2133883d1ddf7a4ed2cd2f5799810ac05
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / stripe_apiroute-0.2.0-py3-none-any.whl
| Download URL | stripe_apiroute-0.2.0-py3-none-any.whl |
|---|---|
| Size | 5.1 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
53c5286a6cc2524a29725a4f366fbf6f5e5d3d987992496942c240af4099a74b
|
|
BLAKE2b-256 checksum How to use checksums |
de9b074044da56542ec67b13627538613272fc5ea45123e9260561ece8d8da21
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for stripe-apiroute 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.