mrkeyoor.com_
Mon 21 Sept 01:58 UTC
PyPIWeb Backendupdated 20 Sept 2026

stripe review

stripe is Stripe's official Python SDK, with generated services and resource types for payments, Checkout, billing, Connect, issuing, tax, and the rest of the public API. StripeClient is the current entry point; request methods also have async variants, lists can auto-page, transient network retries can add idempotency keys, and webhook helpers verify signatures. Version 15.5.1 clarifies StripeObject.to_dict behavior. The preceding 15.5.0 adds async v2 auto-pagination, event parsing helpers for already-verified payloads, a webhook signature-header generator for tests, and a major_api_version constant. Our Python 3.12 install imported successfully and included py.typed.

Verdict

Use stripe for a real Stripe integration; signature verification, pagination, idempotent retries, and generated API coverage outweigh the 17 MB measured install in most payment backends. Scope credentials through StripeClient, pin upgrades deliberately, and never infer payment success from a browser redirect.

We installed it

Lab card: what happened when we installed stripeScreenshot of stripe documentation
Install✓ · 0.4s7 packages on disk · 17 MB
Importimport stripe in 0.51s · pure Python · py.typed · requires Python >=3.9
Known vulns0(pip-audit)

Answers from our run

Does stripe install cleanly?

Yes. In a fresh container with an empty cache, pip install stripe finished in 0.4s, leaving 7 packages and 17 MB on disk. pip-audit reported no known vulnerabilities.

What does stripe need to run?

Python >=3.9, and nothing compiled: it is pure Python. In our run import stripe succeeded in 0.51s, and the package ships py.typed for type checkers.

stripe or dj-stripe: which should you use?

dj-stripe: Use it in Django when Stripe objects should be mirrored into database models through webhook-driven synchronization. Use stripe for a real Stripe integration; signature verification, pagination, idempotent retries, and generated API coverage outweigh the 17 MB measured install in most payment backends.

When should you not use stripe?

The service uses another payment processor. Braintree or Adyen SDKs follow their own APIs and account models

API stability3/5StripeClient and its v1 service tree are the intended modern interface, while the older module-level resource calls remain available during a long transition. Major package versions track Stripe API changes, and the project explicitly excludes type annotations from semantic-version guarantees. A minor update can therefore break static checks even when runtime behavior remains compatible, making minor-range pins sensible for strict CI.
Docs5/5Stripe's API reference generates Python examples per endpoint and links object fields to request and response semantics. The SDK README explains clients, retries, transports, proxies, logging, telemetry, types, previews, raw requests, and async calls. Migration guides cover major transitions. The remaining trap is old third-party material using global configuration, so examples should be checked against the current StripeClient form.
Maintenance5/5GitHub reports 2,034 stars, 24 open issues and pull requests, an unarchived repository, and a latest push on August 25, 2026. Stable 15.5.1 shipped on August 18, eight days after 15.5.0, while separate alpha releases track private previews. Current work includes v2 async pagination, event helpers, generated API updates, test signature utilities, and documentation corrections.
Ecosystem5/5The supplied weekly estimate is 9,973,608 downloads. Stripe's own documentation, Django integrations such as dj-stripe, billing frameworks, and many SaaS codebases assume this SDK or its resource naming. Because it is generated by the API provider, new Stripe products arrive here directly. That ecosystem value disappears if the processor is Braintree or Adyen, where their official client is the correct dependency.

Use it if

  • A Python backend calls Stripe and needs generated methods, resource objects, pagination, retries, and typed request parameters
  • Webhook requests must be authenticated from their raw bytes before business code handles an event
  • An async service wants _async methods and explicit HTTP client selection rather than wrapping blocking payment calls
  • Connect calls need a per-request connected-account header without sharing mutable global API-key state
Skip it if

Setup reality

We installed stripe 15.5.1 in a fresh Python 3.12 Bookworm container. The install finished in 0.4 seconds and left 7 packages using 17 MB. It declares 3 direct dependencies, requires Python 3.9 or newer, and is pure Python. The distribution includes py.typed and reports the MIT License. Importing stripe took 0.51 seconds. pip-audit found no known vulnerabilities.

Create one StripeClient with a restricted secret key from a secret store. Do not put sk_live credentials in source, logs, browser code, or snippets. StripeClient keeps key, account, retry, proxy, and HTTP transport choices together. The older global stripe.api_key path still appears in many examples, but mixing it with explicit clients makes it harder to tell which account and retry policy a call uses. Request telemetry is enabled by default and can be turned off with stripe.enable_telemetry.

Synchronous and asynchronous calls can use different HTTP backends. Install the async extra and construct the chosen client explicitly when an application mixes frameworks or strict dependency pins. max_network_retries handles connection failures and selected responses; its generated idempotency keys cover retries performed inside the SDK. A queue or application retry must provide its own stable idempotency key based on the business operation.

Webhook verification needs the exact raw request body, the Stripe-Signature header, and the endpoint's whsec secret. JSON middleware that parses and serializes before verification breaks the signature. Types describe the API version bundled with the SDK. Overriding stripe_version or receiving older-version webhook payloads can make runtime fields differ from annotations. Pin a minor range when type-check failures must not arrive through an unattended update.

Patterns

Create an explicit Stripe client client-setup

import os
from stripe import StripeClient

client = StripeClient(
    os.environ["STRIPE_SECRET_KEY"],
    max_network_retries=2,
)

customers = client.v1.customers.list(params={"limit": 3})

Keep credentials and retry settings on the client. Internal retries are disabled until max_network_retries is set.

Create a PaymentIntent create-payment-intent

intent = client.v1.payment_intents.create(
    params={
        "amount": 2000,
        "currency": "usd",
        "automatic_payment_methods": {"enabled": True},
    },
)
# send intent.client_secret to your frontend to confirm
return {"clientSecret": intent.client_secret}

Amounts use the currency's smallest unit. StripeClient services accept request data through params.

Start a hosted Checkout session checkout-session

session = client.v1.checkout.sessions.create(
    params={
        "mode": "payment",
        "line_items": [{"price": "price_1ABC...", "quantity": 1}],
        "success_url": "https://example.com/thanks?session_id={CHECKOUT_SESSION_ID}",
        "cancel_url": "https://example.com/cart",
    },
)
return redirect(session.url, code=303)

A success redirect is not payment proof. Fulfill the order only after a verified webhook reports completion.

Verify a webhook event verify-webhook-signature

import stripe
from flask import request

@app.post("/stripe/webhook")
def webhook():
    payload = request.get_data()  # raw bytes, not request.json
    sig = request.headers.get("Stripe-Signature", "")
    try:
        event = client.construct_event(payload, sig, WEBHOOK_SECRET)
    except stripe.SignatureVerificationError:
        return "bad signature", 400

    if event.type == "checkout.session.completed":
        fulfill(event.data.object)
    return "", 200

Pass the untouched request bytes and the endpoint whsec secret; an API key cannot verify the signature.

Iterate all pages lazily auto-pagination

for customer in client.v1.customers.list(
    params={"limit": 100},
).auto_paging_iter():
    process(customer)

limit controls page size rather than total records. Converting the iterator to a list can issue many requests and retain every object.

Supply an application idempotency key idempotency-key

intent = client.v1.payment_intents.create(
    params={"amount": 2000, "currency": "usd"},
    options={"idempotency_key": f"order-{order.id}-charge"},
)

SDK-generated keys protect its internal retries only. Reuse a business-operation key when a job may run again.

Classify Stripe failures error-handling

import stripe

try:
    intent = client.v1.payment_intents.create(params={...})
except stripe.CardError as e:
    show_user(e.user_message)  # safe to display
except stripe.RateLimitError:
    retry_later()
except stripe.InvalidRequestError as e:
    log.error("bad params: %s (param=%s)", e, e.param)
    raise
except stripe.StripeError as e:
    log.error("stripe failure, request_id=%s", e.request_id)
    raise

Show only user-safe messages and log request_id so Stripe support can trace the API call.

Override the API version deliberately pin-api-version

client = StripeClient(
    os.environ["STRIPE_SECRET_KEY"],
    stripe_version="2019-02-19",  # or per request:
)
client.v1.customers.list(
    options={"stripe_version": "2019-02-19"},
)

The SDK annotations follow its bundled API version, so an override can make runtime objects disagree with static types.

Call Stripe asynchronously async-usage

import stripe
from stripe import StripeClient

client = StripeClient(
    os.environ["STRIPE_SECRET_KEY"],
    http_client=stripe.HTTPXClient(),
)

async def get_customer(cid: str):
    return await client.v1.customers.retrieve_async(cid)

async def all_customers():
    page = await client.v1.customers.list_async(params={"limit": 100})
    async for c in page.auto_paging_iter():
        yield c

Use the _async method and an explicit async HTTP client; avoid accidental blocking calls in an event loop.

Scope a Connect request connect-account

account_intent = client.v1.payment_intents.create(
    params={"amount": 2000, "currency": "usd"},
    options={"stripe_account": "acct_1ABC..."},
)

A per-request stripe_account option avoids turning the platform client into a connected-account client.

Expand a nested resource expand-nested-objects

sub = client.v1.subscriptions.retrieve(
    "sub_1ABC...",
    params={"expand": ["latest_invoice.payment_intent", "customer"]},
)
status = sub.latest_invoice.payment_intent.status

Unexpanded fields may be identifier strings. Expand only the objects the response handler actually reads.

Call an endpoint missing from generated services raw-request

response = client.raw_request(
    "post",
    "/v1/beta_endpoint",
    param=123,
    stripe_version="2022-11-15; feature_beta=v3",
)
obj = client.deserialize(response, api_mode="V1")

raw_request trades typed parameters and resources for early access; deserialize returns a dynamic StripeObject.

Alternatives

PackageRegistryPick it when
dj-stripePyPIUse it in Django when Stripe objects should be mirrored into database models through webhook-driven synchronization.
braintreePyPIUse it when the payment account and checkout flow run on Braintree rather than Stripe.
AdyenPyPIUse it when an Adyen merchant account and its payment APIs are the system of record.
httpxPyPIUse it to own a narrow REST wrapper when only a few Stripe endpoints justify code generation and SDK upgrades.

More web backend guides

urllib3 · requests · ws · anyio · httpx · undici · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.