Skip to main content

python-getpaid-stripe

License: MIT

Stripe payment processor for the python-getpaid ecosystem, wrapping Stripe Checkout Sessions (payment mode) via the official stripe-python SDK.

Design and rationale live in SPEC.md; research backing in docs/research/.

Key features

  • Hosted checkout — prepare_transaction() creates a payment-mode Checkout Session and returns a redirect URL
  • Webhook handling — signature verification via stripe.Webhook.construct_event over the raw body; semantic mapping where payment_intent.* events are authoritative for money-state
  • Pre-auth / manual capture — charge() (full or partial capture, remainder auto-released) and release_lock(); the first getpaid plugin to exercise core's pre-auth FSM states
  • Refunds — full and multiple partial refunds; status-driven webhook mapping handles late failures and Stripe-generated expiry refunds
  • Radar fraud reviews — review.opened/closed map to core FraudEvents
  • Status polling — fetch_payment_status() PULL flow, doubling as the authorization-expiry backstop
  • Simulator plugin — a local Stripe stand-in for python-getpaid-simulator with a fake hosted checkout, real HMAC webhook signatures, and time-travel ops

Installation

pip install python-getpaid-stripe

With the local simulator plugin:

pip install python-getpaid-stripe[simulator]

Configuration

Setting Type Required Default Notes
api_key str yes — sk_test_… / sk_live_… / rk_…; validated at construction
webhook_secret str yes — whsec_…, per-endpoint, test/live distinct; validated at construction
success_url str template yes — {payment_id} is formatted by the plugin; Stripe's literal {CHECKOUT_SESSION_ID} is passed through
cancel_url str template yes — same semantics
capture_method "automatic" | "manual" no "automatic" per-payment override: prepare_transaction(capture_method="manual")
session_expires_in int minutes (30–1440) no Stripe's 24 h maps to Checkout expires_at
max_network_retries int no 2 safe: the SDK auto-generates idempotency keys

There is no publishable key setting (nothing in a hosted-Checkout flow consumes one) and no sandbox flag: test vs live mode is derived from the API key prefix (processor.is_sandbox). A flag that can contradict the key is a lie waiting to happen.

accepted_currencies is a broad default list of Stripe presentment currencies; availability is per account country — subclass the processor to narrow it.

Webhook endpoint (Stripe Dashboard)

Point a webhook endpoint at your framework adapter's callback URL and enable exactly these events:

checkout.session.completed
checkout.session.expired
payment_intent.amount_capturable_updated
payment_intent.succeeded
payment_intent.payment_failed
payment_intent.canceled
refund.created
refund.updated
refund.failed
review.opened
review.closed

The framework adapter must pass the raw request body to verify_callback(..., raw_body=...) — Stripe signatures are computed over the raw bytes. Only classic v1 snapshot payloads are supported; v2 "thin" events are rejected.

Manual capture (pre-auth)

Opt in per configuration or per payment. The flow:

  1. prepare_transaction(capture_method="manual") — the buyer authorizes; payment_intent.amount_capturable_updated locks the payment (LOCKED).
  2. charge() captures the full locked amount; charge(amount) captures partially and Stripe auto-releases the remainder. Returns async_call=True — the authoritative PAYMENT_CAPTURED arrives via payment_intent.succeeded.
  3. release_lock() cancels the intent and returns the full locked amount; payment_intent.canceled confirms LOCK_RELEASED.

Operator note — authorization expiry: card authorizations are valid for ~7 days (variance: Visa MIT 5 days, some in-person 2, Japan 30). The lock's provider_data["locked_at"] timestamp is stamped when LOCKED is applied, so your application can schedule capture-or-release. There is no reliable expiry webhook; the deterministic detection path is fetch_payment_status() (a canceled manual-capture intent maps to LOCK_RELEASED). Polling cadence belongs to the application — this plugin ships no scheduler. Note that manual capture also narrows the payment methods Stripe offers (cards, Klarna, PayPal yes; ACH, iDEAL no).

Refunds

start_refund() refunds the full captured amount, start_refund(amount) a part of it (multiple partials allowed). The refund id is stored in provider_data["refund_id"] (latest refund only). Refund reason is deliberately not exposed — Stripe's fraudulent value has card-block side effects.

cancel_refund() effectively always returns False for card payments: only refunds in requires_action (bank-transfer-style methods) are API-cancelable; card refunds can only be canceled from the Stripe Dashboard.

Simulator plugin

With the simulator extra installed, python-getpaid-simulator auto-discovers the stripe plugin. Configuration via environment:

SIMULATOR_STRIPE_API_KEY        (default sk_test_sim_stripe_key)
SIMULATOR_STRIPE_WEBHOOK_SECRET (default whsec_sim_stripe_secret)
SIMULATOR_STRIPE_NOTIFY_URL     (webhook delivery target)

Point the processor at the simulator with the internal api_base config key. The fake hosted checkout offers pay / pay-delayed / decline / abandon; POST /sim/stripe/ops/{order_id} forces transitions with no natural actor (expire_session, expire_auth time-travel, settle_delayed / fail_delayed, fail_refund, set_refund_mode, open_review / close_review). Webhooks carry genuine HMAC Stripe-Signature headers plus deliberate ignore-list traffic (charge.*, checkout.session.async_payment_*) so the processor's ignore behavior is exercised under realistic fire.

Development

uv sync --all-extras
uv run pytest
uv run ruff check .
uv run ty check

License

MIT

Metadata

Release files for python-getpaid-stripe 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for python-getpaid-stripe 0.2.1
File Size Uploaded
python_getpaid_stripe-0.2.1.tar.gz 158.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for python-getpaid-stripe 0.2.1
File Interpreter ABI Platform
python_getpaid_stripe-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 182.7 kB

Release files / python_getpaid_stripe-0.2.1.tar.gz

Download URL python_getpaid_stripe-0.2.1.tar.gz
Size 158.3 kB
Tags Source
SHA-256 checksum
How to use checksums
7b390e4da3d3cbc888d353d0f85b17632e245f044eb6022f4d695a2be78b1cde
BLAKE2b-256 checksum
How to use checksums
4e0f999141454c4d284f882553b200d6e3dc24f80b42d5c56b64c8500b6c85fc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.14

Release files / python_getpaid_stripe-0.2.1-py3-none-any.whl

Download URL python_getpaid_stripe-0.2.1-py3-none-any.whl
Size 24.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1677a04b8b0cc5e88c3be09fb9921992f7aa87e096eeb7d7a63e56be2ca81ded
BLAKE2b-256 checksum
How to use checksums
321a93156adc3594f2fb51dd280052c94a753685d9e9fe50f677b8213caa118f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page