Currently, our project uses FastAPI as the backend and Vue as the frontend. We generate a payment intent ID on the backend, and the frontend creates the corresponding payment using this ID. After the payment is successful, Stripe's webhook sends the event to the backend API. However, we are encountering some issues during the payment process on the frontend. I will first post some code:
Backend code:
@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__)
Frontend code:
import { 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);
});
});
}
}
Error message:
{
"code": "resource_missing",
"doc_url": "https://stripe.com/docs/error-codes/resource-missing",
"message": "No such PaymentMethod: 'pi_...'; It's possible this PaymentMethod exists on one of your connected accounts, in which case you should retry this request on that connected account. Learn more at https://stripe.com/docs/connect/authentication",
"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"
}
From the error message, it can be seen that the error indicates requires_payment_method. However, how should the payment_method be created? The key issue is that we do not plan to use Stripe's Elements to collect user card information. How should we handle this? I have checked Stripe's documentation, but I did not find the relevant solution, possibly due to my limited English proficiency and missing some key information.
I hope to receive some guidance. Thank you very much for your help in advance, especially for taking the time to assist me amidst your busy schedule. Your support and insights are greatly appreciated. Thanks a lot!
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.