mirror of
https://github.com/wshobson/agents.git
synced 2026-03-18 09:37:15 +00:00
Compare commits
3 Commits
5d65aa1063
...
payment-el
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94d1aba17a | ||
|
|
204e8129aa | ||
|
|
2b8e3166a1 |
@@ -21,19 +21,21 @@ Master Stripe payment processing integration for robust, PCI-compliant payment f
|
||||
|
||||
### 1. Payment Flows
|
||||
|
||||
**Checkout Session (Hosted)**
|
||||
**Checkout Sessions**
|
||||
|
||||
- Stripe-hosted payment page
|
||||
- Minimal PCI compliance burden
|
||||
- Fastest implementation
|
||||
- Supports one-time and recurring payments
|
||||
- Recommended for most integrations
|
||||
- Supports all UI paths:
|
||||
- Stripe-hosted checkout page
|
||||
- Embedded checkout form (`ui_mode='embedded'`)
|
||||
- Custom UI with Elements (Payment Element, Express Checkout Element) using `ui_mode='custom'`
|
||||
- Provides built-in checkout capabilities (line items, discounts, tax, shipping, address collection, saved payment methods, and checkout lifecycle events)
|
||||
- Lower integration and maintenance burden than Payment Intents
|
||||
|
||||
**Payment Intents (Custom UI)**
|
||||
**Payment Intents (Bespoke control)**
|
||||
|
||||
- Full control over payment UI
|
||||
- You calculate the final amount with taxes, discounts, subscriptions, and currency conversion yourself.
|
||||
- More complex implementation and long-term maintenance burden
|
||||
- Requires Stripe.js for PCI compliance
|
||||
- More complex implementation
|
||||
- Better customization options
|
||||
|
||||
**Setup Intents (Save Payment Methods)**
|
||||
|
||||
@@ -77,7 +79,6 @@ stripe.api_key = "sk_test_..."
|
||||
|
||||
# Create a checkout session
|
||||
session = stripe.checkout.Session.create(
|
||||
payment_method_types=['card'],
|
||||
line_items=[{
|
||||
'price_data': {
|
||||
'currency': 'usd',
|
||||
@@ -109,7 +110,6 @@ def create_checkout_session(amount, currency='usd'):
|
||||
"""Create a one-time payment checkout session."""
|
||||
try:
|
||||
session = stripe.checkout.Session.create(
|
||||
payment_method_types=['card'],
|
||||
line_items=[{
|
||||
'price_data': {
|
||||
'currency': currency,
|
||||
@@ -136,11 +136,76 @@ def create_checkout_session(amount, currency='usd'):
|
||||
raise
|
||||
```
|
||||
|
||||
### Pattern 2: Custom Payment Intent Flow
|
||||
### Pattern 2: Checkout Sessions with Payment Element
|
||||
|
||||
```python
|
||||
def create_checkout_session_for_elements(amount, currency='usd'):
|
||||
"""Create a checkout session configured for Payment Element."""
|
||||
session = stripe.checkout.Session.create(
|
||||
mode='payment',
|
||||
ui_mode='custom',
|
||||
line_items=[{
|
||||
'price_data': {
|
||||
'currency': currency,
|
||||
'product_data': {'name': 'Purchase'},
|
||||
'unit_amount': amount,
|
||||
},
|
||||
'quantity': 1,
|
||||
}],
|
||||
return_url='https://yourdomain.com/complete?session_id={CHECKOUT_SESSION_ID}'
|
||||
)
|
||||
return session.client_secret # Send to frontend for stripe.initCheckout()
|
||||
|
||||
# Frontend (JavaScript)
|
||||
"""
|
||||
const stripe = Stripe('pk_test_...');
|
||||
|
||||
// initCheckout() is synchronous; loadActions() is async
|
||||
const checkout = stripe.initCheckout({clientSecret});
|
||||
const loadActionsResult = await checkout.loadActions();
|
||||
|
||||
if (loadActionsResult.type === 'success') {
|
||||
const {actions} = loadActionsResult;
|
||||
const session = actions.getSession();
|
||||
|
||||
const button = document.getElementById('pay-button');
|
||||
const checkoutContainer = document.getElementById('checkout-container');
|
||||
const emailInput = document.getElementById('email');
|
||||
const emailErrors = document.getElementById('email-errors');
|
||||
const errors = document.getElementById('confirm-errors');
|
||||
|
||||
// Display grand total (amount in smallest currency unit, e.g. cents)
|
||||
checkoutContainer.append(`Total: ${session.total.total.amount}`);
|
||||
|
||||
// Mount Payment Element
|
||||
const paymentElement = checkout.createPaymentElement();
|
||||
paymentElement.mount('#payment-element');
|
||||
|
||||
// Store email for submission
|
||||
emailInput.addEventListener('blur', () => {
|
||||
actions.updateEmail(emailInput.value).then((result) => {
|
||||
if (result.error) emailErrors.textContent = result.error.message;
|
||||
});
|
||||
});
|
||||
|
||||
// Handle form submission
|
||||
button.addEventListener('click', () => {
|
||||
actions.confirm().then((result) => {
|
||||
if (result.type === 'error') errors.textContent = result.error.message;
|
||||
});
|
||||
});
|
||||
}
|
||||
"""
|
||||
```
|
||||
|
||||
### Pattern 3: Payment Intents with Payment Element (Bespoke Control)
|
||||
|
||||
Use this when you need full control over the payment flow and cannot use Checkout Sessions
|
||||
(e.g., you have your own tax, discount, or subscription calculation engine).
|
||||
|
||||
```python
|
||||
def create_payment_intent(amount, currency='usd', customer_id=None):
|
||||
"""Create a payment intent for custom checkout UI."""
|
||||
"""Create a payment intent for bespoke checkout UI with Payment Element."""
|
||||
intent = stripe.PaymentIntent.create(
|
||||
amount=amount,
|
||||
currency=currency,
|
||||
@@ -148,40 +213,33 @@ def create_payment_intent(amount, currency='usd', customer_id=None):
|
||||
automatic_payment_methods={
|
||||
'enabled': True,
|
||||
},
|
||||
metadata={
|
||||
'integration_check': 'accept_a_payment'
|
||||
}
|
||||
)
|
||||
return intent.client_secret # Send to frontend
|
||||
|
||||
# Frontend (JavaScript)
|
||||
"""
|
||||
const stripe = Stripe('pk_test_...');
|
||||
const elements = stripe.elements();
|
||||
const cardElement = elements.create('card');
|
||||
cardElement.mount('#card-element');
|
||||
|
||||
const {error, paymentIntent} = await stripe.confirmCardPayment(
|
||||
clientSecret,
|
||||
{
|
||||
payment_method: {
|
||||
card: cardElement,
|
||||
billing_details: {
|
||||
name: 'Customer Name'
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (error) {
|
||||
// Handle error
|
||||
} else if (paymentIntent.status === 'succeeded') {
|
||||
// Payment successful
|
||||
}
|
||||
"""
|
||||
```
|
||||
|
||||
### Pattern 3: Subscription Creation
|
||||
```javascript
|
||||
// Frontend: Mount Payment Element and confirm via Payment Intents
|
||||
const stripe = Stripe('pk_test_...');
|
||||
const elements = stripe.elements({clientSecret});
|
||||
|
||||
const paymentElement = elements.create('payment');
|
||||
paymentElement.mount('#payment-element');
|
||||
|
||||
document.getElementById('pay-button').addEventListener('click', async () => {
|
||||
const {error} = await stripe.confirmPayment({
|
||||
elements,
|
||||
confirmParams: {
|
||||
return_url: 'https://yourdomain.com/complete',
|
||||
},
|
||||
});
|
||||
|
||||
if (error) {
|
||||
document.getElementById('errors').textContent = error.message;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Pattern 4: Subscription Creation
|
||||
|
||||
```python
|
||||
def create_subscription(customer_id, price_id):
|
||||
@@ -204,7 +262,7 @@ def create_subscription(customer_id, price_id):
|
||||
raise
|
||||
```
|
||||
|
||||
### Pattern 4: Customer Portal
|
||||
### Pattern 5: Customer Portal
|
||||
|
||||
```python
|
||||
def create_customer_portal_session(customer_id):
|
||||
@@ -414,7 +472,7 @@ def test_payment_flow():
|
||||
amount=1000,
|
||||
currency='usd',
|
||||
customer=customer.id,
|
||||
payment_method_types=['card']
|
||||
automatic_payment_methods={'enabled': True},
|
||||
)
|
||||
|
||||
# Confirm with test card
|
||||
|
||||
Reference in New Issue
Block a user