Asked 1 month ago by CosmicScientist063
How can I handle Stripe payment methods without using Stripe Elements in FastAPI and Vue?
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
Asked 1 month ago by CosmicScientist063
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
Our project uses FastAPI for the backend and Vue for the frontend to process Stripe payments. We generate a payment intent on the backend and use its client secret on the frontend to confirm the payment. Once the payment is successful, Stripe sends a webhook to our backend API.
Below is the backend code:
PYTHON@router.post("/create_payment_intent") async def create_payment_intent( request: Request, order_id: str = Form(...), order_amount: int = Form(...), currency: str = Form("gbp") ): metadata = { 'user_id': "", 'order_id': order_id } # Create payment intent intent = stripe.PaymentIntent.create( amount=order_amount, currency=currency, receipt_email=user_email, metadata=metadata, automatic_payment_methods={'enabled': True} ) res = { "client_secret": intent.client_secret, "payment_intent_id": intent.id } return JSONResponse(RestResult(code=Code.TRUE, msg=Message.SUCCESS_CREATE_PAYMENT_INTENT, data=res).__dict__)
And here is the frontend code:
JAVASCRIPTimport { RequestApi } from '@/api/RequestApi'; import { loadStripe } from '@stripe/stripe-js'; export class StripeUtil { static pay(params: any) { return new Promise((resolve, reject) => { RequestApi.createPayment(params).then(async res => { const stripe = await loadStripe(import.meta.env.VITE_STRIPE_KEY); if (!stripe) { return reject('stripe load failed'); } const { client_secret, payment_intent_id } = res.data; const { error } = await stripe.confirmPayment({ clientSecret: client_secret, confirmParams: { payment_method: payment_intent_id, return_url: 'https://example.com/order/123/complete', }, }); if (error.type) { showDialog({ message: error.message }).then(); reject(error.message); } }).catch(error => { return reject(error); }); }); } }
You receive the following error message:
JSON{ "code": "resource_missing", "doc_url": "https://stripe.com/docs/error-codes/resource-missing", "message": "No such PaymentMethod: 'pi_...'...", "param": "payment_method", "payment_intent": { "id": "pi_...", "object": "payment_intent", "amount": 1512, "amount_details": { "tip": {} }, "automatic_payment_methods": { "allow_redirects": "always", "enabled": true }, "canceled_at": null, "cancellation_reason": null, "capture_method": "automatic_async", "client_secret": "pi_..._secret_...", "confirmation_method": "automatic", "created": 1731412378, "currency": "gbp", "description": null, "last_payment_error": null, "livemode": false, "next_action": null, "payment_method": null, "payment_method_configuration_details": null, "payment_method_types": [ "card" ], "processing": null, "receipt_email": "test@gmail.com", "setup_future_usage": null, "shipping": null, "source": null, "status": "requires_payment_method" }, "request_log_url": "https://dashboard.stripe.com/test/logs/req_fsqWt4IIR3rXhM?t=1731412381", "type": "invalid_request_error" }
The error indicates that the PaymentIntent is in the state 'requires_payment_method', and that Stripe is unable to find the PaymentMethod. This appears to be caused by passing the PaymentIntent ID as the payment_method during payment confirmation, which is incorrect. Since we do not plan to use Stripe's Elements to collect card details directly, how should we correctly create or supply the payment method? I have reviewed Stripe's documentation but haven’t found a clear solution, possibly due to language limitations.
I appreciate any guidance to resolve this issue. Thank you for your help!
Comments 0
•Answers 2
•Views 111
Answer by TychoAI Agent • 1 month ago
Below is some guidance on resolving your issue:
Your code is mistakenly passing the PaymentIntent ID as the payment_method during payment confirmation. The error message:
"No such PaymentMethod: 'pi_...'"
indicates that Stripe is trying (and failing) to find a PaymentMethod with that ID.
When you create a PaymentIntent with automatic payment methods enabled, Stripe expects to collect payment details via one of its supported client-side methods (for example, with Stripe Elements or one of the mobile SDKs). In that flow, your client collects card details, and Stripe creates a PaymentMethod object behind the scenes.
Alternatively, if you wish to supply a PaymentMethod yourself, you must create it as a separate object (either on the client or the backend) and then pass its ID when confirming the PaymentIntent.
Since you mentioned that you do not plan to use Stripe Elements to collect card details, here are a couple of approaches you can consider:
Use an Alternative UI (e.g. Stripe Checkout):
If you prefer not to handle card details directly in your Vue app, you might use Stripe Checkout. This hosted solution securely collects payment information without you handling the PCI burden.
Create the PaymentMethod on the Server:
If you have an alternative way to collect card details (for example, via a PCI-compliant gateway or mobile SDK), you can create the PaymentMethod on the backend.
For example, you could call the Payment Methods API using server-side code:
PYTHONpayment_method = stripe.PaymentMethod.create( type="card", card={ "number": "4242424242424242", "exp_month": 12, "exp_year": 2025, "cvc": "123", }, )
Then use its ID when confirming the PaymentIntent.
Note: This approach requires you to ensure you meet PCI compliance since you are handling raw card data.
Leverage Automatic Payment Methods Without Manual Creation:
Since you’re already creating the PaymentIntent with
PYTHONautomatic_payment_methods={'enabled': True}
Stripe’s SDK is designed to handle the collection of payment details for you. In that case, you should remove the payment_method
field from your confirmPayment
call. Your client code could instead look like this:
JAVASCRIPTconst { error } = await stripe.confirmPayment({ clientSecret: client_secret, confirmParams: { return_url: 'https://example.com/order/123/complete', }, }); if (error) { // handle error (e.g., show dialog to the user) reject(error.message); }
With this approach, Stripe expects that the customer will complete the payment details securely via the provided client secret and possibly a redirect (if required).
Choose the approach that best suits your security and user experience needs. If you’re looking to avoid handling card data directly, Stripe Checkout might be a great option. Otherwise, ensure your method for creating a PaymentMethod is separate from your PaymentIntent ID.
I hope this clarification helps clear things up!
Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?
No comments yet.
Answer by LunarAstronaut962 • 4 months ago
Stripe recommends utilising Checkout, Elements, or our mobile SDK which are a secure and PCI compliant way to collect payment method details.
If you would still like to collect the details on your own and create the payment method via the API, you will need to ensure you’re SAQ D compliant and can follow the steps in this document to enable access to raw card data APIs.
No comments yet.
No comments yet.