FastAPI payment checkout library — Python port of awesome-node-checkout
Project description
awesome-python-checkout
FastAPI payment checkout library — a faithful Python port of awesome-node-checkout.
Drop-in payment orchestration for FastAPI — connect any payment provider through a single interface.
Inspired by awesome-python-auth. Same philosophy: no framework lock-in, no DB lock-in, implement one interface and you're done.
Installation
pip install awesome-python-checkout
Quick Start
Standalone (no HTTP framework)
import asyncio
from awesome_python_checkout import CheckoutConfigurator, PayPalProvider, PayPalConfig, PaymentRequest
checkout = CheckoutConfigurator()
checkout.register_provider(
PayPalProvider(PayPalConfig(
client_id="YOUR_CLIENT_ID",
client_secret="YOUR_CLIENT_SECRET",
environment="sandbox",
))
)
async def main():
result = await checkout.create_payment(
"paypal",
PaymentRequest(
amount=49.99,
currency="EUR",
description="Order #1234",
return_url="https://myapp.com/payment/success",
cancel_url="https://myapp.com/payment/cancel",
order_id="ORD-1234",
),
)
print(result.redirect_url) # redirect user to this URL
asyncio.run(main())
FastAPI router mounting
import os
from fastapi import FastAPI
from awesome_python_checkout import (
CheckoutConfigurator,
PayPalProvider, PayPalConfig,
NexiProvider, NexiConfig,
SatispayProvider, SatispayConfig,
)
checkout = CheckoutConfigurator()
checkout \
.register_provider(PayPalProvider(PayPalConfig(
client_id=os.environ["PAYPAL_CLIENT_ID"],
client_secret=os.environ["PAYPAL_CLIENT_SECRET"],
environment="sandbox",
))) \
.register_provider(NexiProvider(NexiConfig(
merchant_id=os.environ["NEXI_MERCHANT_ID"],
mac_key=os.environ["NEXI_MAC_KEY"],
environment="sandbox",
))) \
.register_provider(SatispayProvider(SatispayConfig(
key_id=os.environ["SATISPAY_KEY_ID"],
private_key=open("private.pem").read(),
environment="sandbox",
server_url="https://myapp.com",
)))
app = FastAPI()
app.include_router(checkout.router(), prefix="/checkout")
CheckoutConfig Reference
PayPalConfig
| Field | Type | Default | Description |
|---|---|---|---|
client_id |
str |
required | PayPal OAuth2 client ID |
client_secret |
str |
required | PayPal OAuth2 client secret |
environment |
"sandbox" | "live" |
"sandbox" |
Target environment |
NexiConfig
| Field | Type | Default | Description |
|---|---|---|---|
merchant_id |
str |
required | Nexi merchant alias |
mac_key |
str |
required | Nexi MAC key for SHA-1 signature |
environment |
"sandbox" | "live" |
"sandbox" |
Target environment |
SatispayConfig
| Field | Type | Default | Description |
|---|---|---|---|
key_id |
str |
required | Satispay RSA key ID |
private_key |
str |
required | RSA private key (PEM string) |
environment |
"sandbox" | "live" |
"sandbox" |
Target environment |
server_url |
str |
"" |
Public base URL of your server (used to build the webhook callback URL) |
store |
ITransactionStore |
InMemoryTransactionStore() |
Transaction store for correlating webhooks |
Routes
All routes are mounted under the prefix you choose (e.g. /checkout).
| Method | Path | Description |
|---|---|---|
POST |
/{provider} |
Create a payment |
POST |
/{provider}/execute |
Execute / capture a payment |
GET |
/{provider}/redirect |
Handle provider redirect callback |
GET |
/{provider}/{id} |
Get payment details |
POST |
/{provider}/refund |
Refund a payment |
POST |
/{provider}/webhook |
Handle provider webhook |
Payment Flows
| Flow | Providers | Description |
|---|---|---|
redirect |
PayPal, Nexi | User is redirected to the provider page, then returns with query params |
webhook |
Satispay | Provider calls the webhook URL asynchronously after confirmation |
direct |
(future) | Synchronous processing (card tokenisation, etc.) |
Events
Subscribe to lifecycle events with checkout.on():
checkout \
.on("payment.created", lambda p: print("created", p["paymentId"])) \
.on("payment.completed", lambda p: print("completed", p["paymentId"])) \
.on("payment.failed", lambda p: print("failed", p["error"])) \
.on("payment.refunded", lambda p: print("refunded", p["paymentId"])) \
.on("webhook.received", lambda p: print("webhook", p["data"]))
Async callbacks are also supported:
async def on_completed(payload):
await notify_order_service(payload["paymentId"])
checkout.on("payment.completed", on_completed)
| Event | Payload keys | Fired when |
|---|---|---|
payment.created |
provider, paymentId |
create_payment succeeds |
payment.completed |
provider, paymentId |
execute / redirect / webhook confirms success |
payment.failed |
provider, error |
payment fails |
payment.refunded |
provider, paymentId |
refund succeeds |
webhook.received |
provider, data |
webhook body arrives |
Custom Transaction Store
Implement ITransactionStore to persist transactions in your database:
from awesome_python_checkout import ITransactionStore, TransactionData
class RedisTransactionStore(ITransactionStore):
async def save(self, key: str, data: TransactionData) -> None:
await redis.set(key, data.model_dump_json(), ex=3600)
async def get(self, key: str) -> TransactionData | None:
raw = await redis.get(key)
return TransactionData.model_validate_json(raw) if raw else None
async def delete(self, key: str) -> None:
await redis.delete(key)
Pass the store to the provider config:
from awesome_python_checkout import SatispayProvider, SatispayConfig
provider = SatispayProvider(SatispayConfig(
key_id="...",
private_key="...",
store=RedisTransactionStore(),
))
Custom Provider
Extend BasePaymentProvider to add your own payment gateway:
from awesome_python_checkout import BasePaymentProvider, PaymentRequest, PaymentResult
from typing import Any, Literal
class StripeProvider(BasePaymentProvider):
@property
def name(self) -> str:
return "stripe"
@property
def flow(self) -> Literal["redirect"]:
return "redirect"
async def create_payment(self, request: PaymentRequest) -> PaymentResult:
# call Stripe API …
return PaymentResult(
payment_id="pi_xxx",
status="pending",
provider=self.name,
redirect_url="https://checkout.stripe.com/pay/…",
)
async def execute_payment(self, payment_id: str, data: dict[str, Any]) -> PaymentResult: ...
async def get_payment(self, payment_id: str) -> PaymentResult: ...
async def refund_payment(self, payment_id: str, amount: float | None = None) -> PaymentResult: ...
async def handle_webhook(self, body: Any, headers: dict[str, str]) -> PaymentResult: ...
async def handle_redirect(self, query: dict[str, str]) -> PaymentResult: ...
checkout.register_provider(StripeProvider())
Built-in Providers
| Provider | Flow | Notes |
|---|---|---|
PayPalProvider |
redirect | PayPal Orders API v2 |
NexiProvider |
redirect | Nexi eCommerce DispatcherServlet, MAC SHA-1 |
SatispayProvider |
webhook | Satispay Business API v1, RSA-SHA256 signing |
Angular Integration
Point your Angular app (using ng-awesome-node-auth or any HTTP client) at the FastAPI server:
// Call the checkout API directly from Angular
const result = await http.post('/checkout/paypal', {
amount: 49.99,
currency: 'EUR',
order_id: 'ORD-1234',
return_url: 'https://myapp.com/success',
cancel_url: 'https://myapp.com/cancel',
}).toPromise();
window.location.href = result.redirect_url;
No other changes needed — the FastAPI server handles all provider communication.
Flutter Integration
Call the checkout endpoints from your Flutter app:
final response = await http.post(
Uri.parse('https://your-server.com/checkout/paypal'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
'amount': 49.99,
'currency': 'EUR',
'order_id': 'ORD-1234',
'return_url': 'https://your-server.com/success',
'cancel_url': 'https://your-server.com/cancel',
}),
);
final data = jsonDecode(response.body);
// Open data['redirect_url'] in a WebView or browser
License
MIT
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 awesome_python_checkout-0.1.0.tar.gz.
File metadata
- Download URL: awesome_python_checkout-0.1.0.tar.gz
- Upload date:
- Size: 20.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
16614a4ba9ae3f32112f06e9eddd855d642df07491c1be895d27e9ad0248d503
|
|
| MD5 |
6cac450ca70048f0b3880edd792b0b99
|
|
| BLAKE2b-256 |
0c3ae5b31519c73ed0712db4d139fcb25044360909c41d6a47cbf40739d8b63d
|
Provenance
The following attestation bundles were made for awesome_python_checkout-0.1.0.tar.gz:
Publisher:
publish.yml on nik2208/awesome-python-checkout
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
awesome_python_checkout-0.1.0.tar.gz -
Subject digest:
16614a4ba9ae3f32112f06e9eddd855d642df07491c1be895d27e9ad0248d503 - Sigstore transparency entry: 1461993467
- Sigstore integration time:
-
Permalink:
nik2208/awesome-python-checkout@01d66b87bedf083ef5c23451a90a832c9559ecc3 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/nik2208
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@01d66b87bedf083ef5c23451a90a832c9559ecc3 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file awesome_python_checkout-0.1.0-py3-none-any.whl.
File metadata
- Download URL: awesome_python_checkout-0.1.0-py3-none-any.whl
- Upload date:
- Size: 17.2 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 |
90fe56be5065a4885f299d7630e74f70e3fe911cc6744b36ed4269c3c98f640d
|
|
| MD5 |
294e58ba70844a0ef80fa7e6e8a0db6a
|
|
| BLAKE2b-256 |
2d3019a5b3c26b6a9c6efce8e43628f51f64d88a9b07588989cb237355ba3279
|
Provenance
The following attestation bundles were made for awesome_python_checkout-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on nik2208/awesome-python-checkout
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
awesome_python_checkout-0.1.0-py3-none-any.whl -
Subject digest:
90fe56be5065a4885f299d7630e74f70e3fe911cc6744b36ed4269c3c98f640d - Sigstore transparency entry: 1461993478
- Sigstore integration time:
-
Permalink:
nik2208/awesome-python-checkout@01d66b87bedf083ef5c23451a90a832c9559ecc3 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/nik2208
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@01d66b87bedf083ef5c23451a90a832c9559ecc3 -
Trigger Event:
workflow_dispatch
-
Statement type: