mirror of
https://github.com/wshobson/agents.git
synced 2026-03-18 09:37:15 +00:00
Update to latest Stripe best practices
This commit is contained in:
@@ -21,19 +21,21 @@ Master Stripe payment processing integration for robust, PCI-compliant payment f
|
|||||||
|
|
||||||
### 1. Payment Flows
|
### 1. Payment Flows
|
||||||
|
|
||||||
**Checkout Session (Hosted)**
|
**Checkout Sessions**
|
||||||
|
|
||||||
- Stripe-hosted payment page
|
- Recommended for most integrations
|
||||||
- Minimal PCI compliance burden
|
- Supports all UI paths:
|
||||||
- Fastest implementation
|
- Stripe-hosted checkout page
|
||||||
- Supports one-time and recurring payments
|
- Embedded checkout form
|
||||||
|
- 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
|
- Requires Stripe.js for PCI compliance
|
||||||
- More complex implementation
|
|
||||||
- Better customization options
|
|
||||||
|
|
||||||
**Setup Intents (Save Payment Methods)**
|
**Setup Intents (Save Payment Methods)**
|
||||||
|
|
||||||
@@ -109,7 +111,6 @@ def create_checkout_session(amount, currency='usd'):
|
|||||||
"""Create a one-time payment checkout session."""
|
"""Create a one-time payment checkout session."""
|
||||||
try:
|
try:
|
||||||
session = stripe.checkout.Session.create(
|
session = stripe.checkout.Session.create(
|
||||||
payment_method_types=['card'],
|
|
||||||
line_items=[{
|
line_items=[{
|
||||||
'price_data': {
|
'price_data': {
|
||||||
'currency': currency,
|
'currency': currency,
|
||||||
@@ -136,47 +137,64 @@ def create_checkout_session(amount, currency='usd'):
|
|||||||
raise
|
raise
|
||||||
```
|
```
|
||||||
|
|
||||||
### Pattern 2: Custom Payment Intent Flow
|
### Pattern 2: Checkout Sessions with Payment Element
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def create_payment_intent(amount, currency='usd', customer_id=None):
|
def create_checkout_session_for_elements(amount, currency='usd'):
|
||||||
"""Create a payment intent for custom checkout UI."""
|
"""Create a checkout session configured for Payment Element."""
|
||||||
intent = stripe.PaymentIntent.create(
|
session = stripe.checkout.Session.create(
|
||||||
amount=amount,
|
mode='payment',
|
||||||
currency=currency,
|
ui_mode='custom',
|
||||||
customer=customer_id,
|
line_items=[{
|
||||||
automatic_payment_methods={
|
'price_data': {
|
||||||
'enabled': True,
|
'currency': currency,
|
||||||
},
|
'product_data': {'name': 'Purchase'},
|
||||||
metadata={
|
'unit_amount': amount,
|
||||||
'integration_check': 'accept_a_payment'
|
},
|
||||||
}
|
'quantity': 1,
|
||||||
|
}],
|
||||||
|
return_url='https://yourdomain.com/complete?session_id={CHECKOUT_SESSION_ID}'
|
||||||
)
|
)
|
||||||
return intent.client_secret # Send to frontend
|
return session.client_secret # Send to frontend
|
||||||
|
|
||||||
# Frontend (JavaScript)
|
# Frontend (JavaScript)
|
||||||
"""
|
"""
|
||||||
const stripe = Stripe('pk_test_...');
|
const stripe = Stripe('pk_test_...');
|
||||||
const elements = stripe.elements();
|
const appearance = { theme: 'stripe' };
|
||||||
const cardElement = elements.create('card');
|
|
||||||
cardElement.mount('#card-element');
|
|
||||||
|
|
||||||
const {error, paymentIntent} = await stripe.confirmCardPayment(
|
const checkout = stripe.initCheckout({clientSecret});
|
||||||
clientSecret,
|
const loadActionsResult = await checkout.loadActions();
|
||||||
{
|
|
||||||
payment_method: {
|
|
||||||
card: cardElement,
|
|
||||||
billing_details: {
|
|
||||||
name: 'Customer Name'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (error) {
|
if (loadActionsResult.type === 'success') {
|
||||||
// Handle error
|
const session = loadActionsResult.actions.getSession();
|
||||||
} else if (paymentIntent.status === 'succeeded') {
|
const {actions} = loadActionsResult;
|
||||||
// Payment successful
|
|
||||||
|
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 total to user
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user